Java内存结构和垃圾回收

内存结构

java内存结构主要有三大区块:栈内存,堆内存,堆外内存(直接内存)。其中:

1.栈内存主要是存放线程的栈信息,每个线程有独立的线程栈。

2.堆内存有元信息区和对象区,对象区则采用分代的策略,便于垃圾回收。

3.元信息区主要存放类信息,静态变量信息。

4.此外还有堆外内存,这部分内存不受垃圾回收器的管理,其内存管理自成另一套体系。

所有的内存空间之和不能超过物理内存,以及操作系统规定的内存限制。

image.png

栈内存

每个线程拥有独立的线程栈。占中存放线程的调用信息,对象引用,以及基本类型的对象(大小确定的,如int ,short, long, byte, float, double,boolean,char)。

可以通过-Xss 指定每个线程栈的大小,默认会使用jdk自带的大小。

当递归层数过多,或者线程的对象应用过多,可能造成栈内存不足的报错:StackOverFlowError.

堆内存

存放通过new 创建的对象实例。所有线程共享。运行时动态分配内存。jvm会监控对象实例的引用状态等,并采用垃圾回收机制,尽可能优化堆内存的使用,释放无用的对象实例。

垃圾回收

jvm通过垃圾回收来回收堆和方法区中的内存,基本原理就是找到城中不再被使用的对象,然后回收掉这些对象占用的内存。自动回收机制,以使得程序员摆脱内存管理的繁杂事务。垃圾回收有可达性检测,整理无用对象实例,以及分代/分区思想等内容。

可达性检测

即检测对象是否不再被使用。主要有引用计数和跟踪计数两种。

  1. 引用计数器记录对象是否被引用,当计数器为0时,说明对象已经不再被使用,可以回收。但是java中的引用关系非常复杂,存在循环引用的情况,因此引用计数器不适合。

  2. 跟踪计数:执行的时候,从根集合开始扫描对象的引用关系,从节点向下搜索,如果一个对象到根集合没有引用链,那么该对象是不可用的。根集合主要值:虚拟机栈中引用的对象、方法区中类静态属性引用的休想、方法区中敞亮引用的对象、本地方法栈中jni引用的对象。

整理策略

  1. 复制:从根集合中扫描出存活的对象,然后将存活的对象复制到一块新的未使用空间。当存活对象较少时,比较高效。
  2. 标记清除:从根集合开始扫描,标记存活的对象。再扫描整个空间未标价的对象,然后回收,对象无需移动,高效但是有碎片。
  3. 标记压缩:标记形式与“标记清除”一样,但是回收不存在的对象后,会做一次内存整理。成本高但是无碎片。

分代、分区思想

分代和分区思想,将堆内存区分管理,对不同的区块进行不同策略的回收机制,使得生命周期短的对象能够快速被收回,生命周期长的对象能够在适当的时候做统一回收。

年轻代,年老代的设置即时分代和分区思想的一种实现。

垃圾回收器

  1. 串行收集器(Serial):指的是使用一个单线程进行垃圾收集,工作的时候会暂停其他工作线程。

  2. 并行收集器(Parallel):使用多线程完成垃圾收集,工作的时候会暂停其他工作线程。

  3. CMS收集器:并发标记清除,少量时间会暂停其他工作线程,其余时间与工作线程共同执行。

  4. G1收集器:垃圾优先收集器,设计初衷是尽量缩短超大堆(大于4G)时产生的停顿,相对于cms来说内存碎片大大降低,但是也会存在可能会造成停顿时间较长。jdk 1.7u4以上可以使用。不过目前线上还没有使用这种策略。

堆外内存

将对象分配到java虚拟机以外的内存,这部分内存直接受操作系统管理,可以减少受到垃圾回收对应用程序造成的影响。使用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用。

为什么要有堆外内存

减少垃圾回收;加快复制到远程的速度:堆内存在flush到远程时,会先复制到直接内存,然后再发送,而堆外内存少了复制这一步。

堆外内存的问题

内存难以控制

gc触发时机的问题

何时触发minor gc

  1. 当eden区分配内存,发现空间不足,jvm就会触发minor gc
  2. 程序中调用Sysetm.gc()

何时触发cms gc

  1. 老年代或者持久代已经使用的空间达到设定的百分比时(CMSInitiatingOccupancyFraction这个设置old区,perm区也可以设置);
  2. JVM自动触发(JVM的动态策略,也就是悲观策略)(基于之前GC的频率以及旧生代的增长趋势来评估决定什么时候开始执行),如果不希望JVM自行决定,可以通过-XX:UseCMSInitiatingOccupancyOnly=true来禁用

何时触发full gc

  1. 老年代空间不足:java.lang.OutOfMemoryError: java heap space
  2. Perm空间不足:java.lang.OutOfMemoryError: PermGen space
  3. cms gc 时出现 promotion failed 和 concurrent mode failure(cms正在进行,但是老年代内存不足,需要尽快回收老年代的对象)
  4. 统计得到的minor gc 晋升到老年代的平均大小大于老年代的剩余空间
  5. 主动触发 full gc : 执行 jmap -histo:live [pid]

关于内存管理的jvm 参数设置

大小

  • -Xms5g 最小堆内存
  • -Xmx5g 最大堆内存,建议与最小堆内存一致,避免jvm动态调整
  • -Xmn2g 新生代内存
  • -XX:MetaspaceSize=512m jdk8 中元信息的空间大小
  • -XX:MaxMetaspaceSize=512m jdk8 中元信息的最大空间大小
  • -XX:MaxDirectMemorySize=1g 直接内存的最大空间,超过空间,会执行一次内存回收。如果不设置,会和-Xmx基本差不多,导致直接内存和堆内存相加超过物理内存,报内存空间不足的错误。
  • -XX:SurvivorRatio=8 eden和suvivor的比例。例如设置为8,则eden:s0:s1的比例为8:1:1

垃圾回收器策略

  • -XX:+UseConcMarkSweepGC 使用cms(并发标记消除)进行老年代的回收,默认新生代采用ParNew回收
  • -XX:+UseParallelGC 使用并行
  • -XX:+UseSerialGC 串行gc

其他

cms相关的参数

  • -XX:CMSInitiatingOccupancyFraction=75 内存使用率达到75%后,开始cms收集
  • -XX:+UseCMSInitiatingOccupancyOnly 禁用jvm cms的悲观策略,仅根据内存使用率来触发cms
  • -XX:+UseCMSCompactAtFullCollection cms是消除策略,有内存碎片。指定该参数后,在fgc后会整理碎片。
  • -XX:CMSMaxAbortablePrecleanTime =5000
  • -XX:+CMSClassUnloadingEnabled 方法区使用cms,允许对类的元数据进行回收
  • -XX:CMSPermGenSweepingEnabled 方法区使用cms

gc日志相关参数

  • -Xloggc=/gc.log gc日志输出的地址
  • -XX:+PrintGCDetails 开启详细gc模式
  • -XX:+PrintGCDateStamps 每一行前面加上绝对时间戳
  • -XX:+HeapDumpOnOutOfMemoryError 内存溢出时输出堆日志
  • -XX:HeapDumpPath=/heap.hprof 堆日志输出地址

参考资料:
[1]【原】java内存区域理解-初步了解 http://iamzhongyong.iteye.com/blog/1333100
[2] Java HotSpot VM Options http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#Options

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容