Java:内存相关认识

JVM管理的内存

  • 程序计数器(PC):每条线程都有独立的PC
  • JVM栈(Java栈):描述的是Java方法执行的内存模型,每个方法被执行的时候会创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息,也是线程私有的。
  • 本地方法栈:与Native方法相关
  • Java堆:线程共享的内存地址空间,用于存放对象实例,也是GC管理的主要区域。
  • 直接内存:与Native堆相关
  • 方法区:存储已被JVM加载的类信息、常量、静态变量等数据,这个区域的内存回收目标主要针对常量池的回收和类的卸载。方法区也是线程共享的内存区域,虽然被描述为堆的一个逻辑部分,但别名为非堆(Non-Heap)。
  • 运行时常量池:方法区的一部分,常量池存放编辑期生成的各种字面量和符号引用,当类加载后则存放到方法区的运行时常量池。

内存分配规则

  • 对象优先在Eden区分配,Minor GC(新生代GC)后对象不足以放进Survivor区则进入老年代。
  • 大对象直接进入老年代
  • 长期存活的对象讲进入老年代:通过年龄计数器来实现。
  • Survivor同龄对象大小之和大于空间一半,大于这个年龄的对象进入老年代。
  • 判断晋升老年代对象是否大于老年代所剩空间,是则进行Full GC(老年代GC)。

GC回收相关

PC、Java栈、本地方法栈随线程和方法的生命周期,因此内存分配与回收具有确定性。
Java堆和方法区只有在运行期间才能知道需要创建哪里对象,这部分内存分配和回收是动态的,GC关注这部分的内存。通过根追溯(Root Tracing)法,即一条引用链来判断对象存活,来确定是否回收对象(引用计数法不能解决对象相互引用等问题)。方法区主要回收废弃常量和无用的类。

垃圾回收算法:

  • 标记清除算法(Mark-Sweep):回收后会造成内存不连续
  • 复制算法(Copying):将内存分为一块较大的Eden空间和两块较小Survivor空间,将Eden和其中一个Survivor存活对象复制到另外一块Survivor空间,最后回收前面那两个空间。当Survivor空间不够时,由老年代空间进行分配担保。新生代对象中大部分都是朝生夕死的,所以常采用这种算法来回收新生代。
  • 标记整理算法(Mark-Compact):将所有存活对象移向一端,直接清理其他端边界以外的对象。
  • 分代收集:根据对象的存活周期将不同的内存划分为几块,一般分为新生代(Young)和老年代(Old),对不同年代采取不同回收算法。例如,对新生代采取复制算法,对老年代采取标记清除或标记整理回收算法。

一个虚拟机可以有多个不同的GC,如HotSpot就有7种作用于不同年代的GC,另外GC关注的线程数目(单线程还是多线程)也可能是不同的。


Java内存模型

JVM试图定义一种内存模型来屏蔽各种硬件和操作系统间内存访问差异,以实现在各个平台都能达到一致的并发效果。

这里写图片描述

内存间的相互操作:

  • lock
  • unlock
  • read
  • load
  • use
  • assign
  • store
  • write

当一个变量被定义为volatile之后具备两种特效:可视性和禁止重排序。可视性的意思可以粗略理解为,虽然进行了原子操作,但是并不保证另外的线程看到的是最新修改后的值,可视性则保证最新值已经刷新到了主内存。重排序的意思是:不能保证变量赋值操作的顺序与代码的执行顺序一致,如果在本线程内观察,所有的操作都是有序的,即线程内有串行的语义;如果在一个线程观察另外一个线程,由于指令重排序,操作可能是无序的。


参考:
《深入理解Java虚拟机》
http://www.th7.cn/Program/java/201409/276272.shtml

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值