JVM瞎琢磨之内存模型及简单调优思路记录

JVM:java虚拟机,是每个程序员又爱又恨的存在,因为有了它,我们的程序才可以跨平台,但是又因为它的艰涩难懂,让很多人望而却步。
JVM的内存模型有点像咱们国家的土地,由国家统一规划分配,有的是公共用地作为公共场所供所有线程访问,有的是住宅用地线程私有,每个线程分配一小块用于自己的逻辑及数据处理。
JVM的内存可以分为几大块:堆,方法区,栈(虚拟机栈),本地方法栈,程序计数器。
栈,本地方法栈,程序计数器为线程私有,
堆和方法区是所有线程共享,
每创建一个线程,JVM会从栈内存中划出一小块内存给该线程,用于存储线程自己的一些局部变量,方法出口等和运算逻辑、执行状态等相关内容,栈的深度和栈帧的大小相关,相同栈内存下,栈帧越大,栈的深度就越小(栈帧的大小与局部变量和参数的的多少正相关)。
线程中的每个方法,会获得一个栈帧,栈帧是该线程私有栈内存的一小块空间,存储局部变量表,操作数栈,动态链接和方法出口,按照该线程中方法的运行顺序进行压栈,(栈是先进后出的数据结构)如果递归过深,就有可能造成StackOverflowError。
由于线程的运行是采用时间片机制,即一个时刻只能有一个线程占用cpu的一个核,所以线程会进行上下文的切换,这个时候就需要程序计数器对当前线程的执行位置进行记录,方便下次唤醒线程的时候继续执行,所以程序计数器也是线程私有的,确切的说程序计数器根本就不在 RAM上,而是直接划分在CPU上,非常小的一块内存区域,如果执行的时native本地方法,则程序计数器的值为空,此区域时唯一没有任何OutOfMemory的区域。
本地方法栈是为native方法服务的栈内存,运行机制与虚拟机栈的运行机制一致,用于存储每个native方法的执行状态。
堆:堆是所有线程共享的,此内存区域在虚拟机启动时创建,此区域唯一目的就是存放对象实例,而栈存的时对象的引用(指针),栈中同时存储运行逻辑,当调用到某一个变量时通过引用(指针)去堆中找到对应的对象值,是gc的重点区域。在gc角度会将内存区域分为老年代和新生代,其中老年代大约占堆内存的2/3,新生代大约占堆内存的1/3。
新生代又被划分为eden空间(大约占新生代的4/5)和survivor0(约占新生代的1/10),survivor1(约占新生代的1/10)空间。新生代会经常进行minor gc,即eden满了,将gc roots引用链上的所有内容复制到s0空间,所有gc roots引用链上的对象头中的分代年龄+1,其他不在引用链上的内容直接清掉,如果eden又满了,则将eden与s0再次进行minor gc,将gc roots引用链上所有数据移到s1区,所有gc roots引用链上的对象头中的分代年龄+1,清空eden和s0,相当于s0和s1总有一块是空的,用于存储那些不能被垃圾回收的对象,如果对象头中的分代年龄达到15,将会被送入老年代,当老年代也被占满,则会发生full gc,而发生full gc的时候会进行stw(stop the word),导致程序会在stw的时候没有响应影响使用体验,所以如何确定堆内存,e空间大小和s空间大小是避免发生频繁full gc调优程序的一个思考方向(一半可根据每秒数据量估算出一个大小,再根据对象使用时间来处理,这里不做展开)。
如果full gc还是无法释放足够的内存,则系统就会抛出OutOfMemory异常。

–本文原创,如转载请标明出处,谢谢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值