Java知识点(七)JVM内存结构(一张图搞定)

JVM分五大区域:

1.程序计数器   2.Java虚拟机栈   3.本地方法栈   4.方法区   5.堆

下面是直观的绘图 【如有需要请点击放大镜】

=====================================事实上并没有那么简单============================

一、可能发生的ERROR

  • OutOfMemoryError
    • 程序计数器:无

    • Java虚拟机栈: 如果虚拟机栈可扩展,扩展时无法申请到足够内存

    • 本地方法栈:与Java虚拟机栈相同

    • Java堆:堆中没有内存完成实例分配,并且堆无法再进行扩展

    • 方法区(运行时常量池):方法区无法满足内存分配需求(常量池无法申请到内存)

    • 直接内存:内存区域总和大于物理内存总和

  • StackOverflowError
    • 程序计数器:无

    • Java虚拟机栈:线程请求的栈深度大于虚拟机所允许的深度

    • 本地方法栈:与Java虚拟机栈类似

    • Java堆:无

    • 方法区:无

    • 直接内存:无

    • 直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。

      在JDK 1.4中新加入了NIO(Non-blocking IO)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

      诚然,本机直接内存的分配不会受到Java堆大小的限制,但既然是内存,则还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError

 

二、新生代与老年代

java可以细分为新生代和老年代

新生代:生命周期比较短的对象。

老年代:生命周期比较长的对象

GC算法

1、新生代常采用的算法:复制算法

现在商业虚拟机都采用这种收集算法来回收新生代。

新生代的对象98%都是“朝生夕死”,将内存分为一块较大的Eden空间和Survivor 的“From”区,Survivor的“To”区(8:1:1)。

每次使用Eden和其中一块survior,当回收时,将Eden和survior中还存活着的对象一次性地复制到另外一块survior空间上,最后清理掉Eden和刚才用过的survior空间。当Eden空间、from survior和 to survior比例为(8:1:1)时,只有10%的内存被“浪费”。

一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到老年代中。

2、老年代常采用的算法:标记-清除算法 and 标记-整理算法

标记-清除算法

算法分为“标记”和“清除”两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收。

存在问题:

(1)效率问题,标记和清除两个过程的效率都不高。

(2)空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中,需要分配较大对象时,无法找到足够连续的内存而不得不提前触发另一次垃圾回收动作。

标记-整理算法

标记过程和标记-清除算法相同,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

3、关于新生代的参数调优

1)-XX:NewSize和-XX:MaxNewSize

用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。

2)-XX:SurvivorRatio

用于设置Eden和其中一个Survivor的比值,这个值也比较重要。

3)-XX:+PrintTenuringDistribution

这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。

4).-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,“年龄”就加1

 

三、下面是讲故事阶段

HotSpot虚拟机GC算法采用分代收集算法:

1、一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直到GC到来打破了他们平静的生活。GC会逐一问清楚每个对象的情况,有没有钱(此对象的引用)啊,因为GC想赚钱呀,有钱的才可以敲诈嘛。然后富人就会进入Survivor Space(幸存者区),穷人的就直接kill掉。

2、并不是进入Survivor Space(幸存者区)后就保证人身是安全的,但至少可以活段时间。GC会定期(可以自定义)会对这些人进行敲诈,亿万富翁每次都给钱,GC很满意,就让其进入了Genured Gen(养老区)。万元户经不住几次敲诈就没钱了,GC看没有啥价值啦,就直接kill掉了。

3、进入到养老区的人基本就可以保证人身安全啦,但是亿万富豪有的也会挥霍成穷光蛋,只要钱没了,GC还是kill掉。

分区的目的:新生区由于对象产生的比较多并且大都是朝生夕灭的,所以直接采用标记-清理算法。而养老区生命力很强,则采用复制算法,针对不同情况使用不同算法。

非heap区域中Perm Gen中放着类、方法的定义,JVM Stack区域放着方法参数、局域变量等的引用,方法执行顺序按照栈的先入后出方式。

简单来讲,JVM的内存回收过程是这样的:

对象在Eden Space创建,当Eden Space满了的时候,gc就把所有在Eden Space中的对象扫描一次,把所有有效的对象复制到第一个Survivor Space,同时把无效的对象所占用的空间释放。当Eden Space再次变满了的时候,就启动移动程序把Eden Space中有效的对象复制到第二个Survivor Space,同时,也将第一个Survivor Space中的有效对象复制到第二个Survivor Space。如果填充到第二个Survivor Space中的有效对象被第一个Survivor Space或Eden Space中的对象引用,那么这些对象就是长期存在的,此时这些对象将被复制到Permanent Generation。若垃圾收集器依据这种小幅度的调整收集不能腾出足够的空间,就会运行Full GC,此时JVM GC停止所有在堆中运行的线程并执行清除动作。

转载自:https://www.cnblogs.com/sunshisonghit/p/6694590.html

https://blog.csdn.net/jisuanjiguoba/article/details/80156781

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值