JVM的内存结构

 

 

程序计数器:它是较小的一块内存区域,分支、循环、跳转、异常处理和线程恢复等基础功能都依赖计数器。

Java方法栈:栈内存,线程创建时创建,它的生命周期随线程的生命周期,线程结束时栈内存随之释放。局部变量表存放编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double),局部变量表所需的内存空间在编译期间完成分配,在方法运行前,局部变量表所需的内存空间是固定的。

本地方法栈:一个本地方法(Native Method)就是一个java调用非java代码的接口,为java虚拟机提供本地方法的服务。

堆:是被所有线程共享的内存区域。在JVM启动时创建,专门用来保存对象的实例。保存对象实例也是保存对象的属性值,并不保存对象的方法。对象实例在堆分配好后,需在栈中保存一个4字节的Heap内存地址,它用来定位该对象在Heap中的位置。

内存分为两块:permantspace(持久代,永久代)和heapspace。

永久代(permantspace)是在方法区,方法区逻辑上属于堆的一部分,为了与堆区分,又被称为“非堆”。

永久代中主要存放用于存放静态类型数据,如java class,method等。

虚拟机栈(栈中的本地变量表)中引用的对象;方法区中的类静态属性引用的对象、常量引用的对象;本地方法栈JNI(Java Native Interface)中引用的对象可以作为GC Roots的对象。JVM是通过根搜索算法判定对象是否存活的。从GC Roots对象开始向下搜索。若一个对象到GC Roots没有任何引用链相连(不可达)时,证明该对象是不可用的。若两次标记后,对象在finalize()方法中没有重新与引用链上的任何一个对象建立连接,则会被垃圾回收。(注finalize()方法只被系统自动调用一次)

永久代(持久代)内存溢出原因: 比如,1、一些第三方的框架,如spring、hibernate等通过字节码生成技术(CGLib)来增强功能,可能需要更大的方法区来存储动态生成的class类  2、服务器热部署之后,原来的class没有被卸载掉 3、应用程序大,涉及的类多,而所分配的持久代较小也会出现这样的问题

永久代的垃圾回收是以下两类:

1、废弃常量:若字符串“abc”进入了常量池,但当前系统没有任何String对象引用“abc”常量,则当发生内存回收(有必要的情况下)时,常量就会被回收。

2、无用的类:

  1. 该类的所有实例已被回收,Java堆不存在该类实例
  2. 加载该类的classloader已被回收
  3. 加载该类的class对象,没有任何地方引用,且也不能通过反射访问

heapspace分为年轻代和老年代。

年轻带的垃圾回收叫Young GC,老年代的垃圾回收叫Full GC。

在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到老年代。(因此一般老年代可以被认为是存放生命周期较长的对象)

 

垃圾回收算法:

  1. 标记-清除算法(Mark-Swap):标记清除后会产生大量的碎片,以后分配内存较大的对象可能会找不到足够大的连续内存空间,从而导致下一次GC
  2. 复制算法:由于新生代的对象生命周期较短,老年代的对象存活率较高,把内存空间分成1块Eden空间和2块Survivor空间。垃圾回收时,把Eden和Survivor空间中活着的对象一次性复制到另一块Survivor空间中,再清理Eden和Survivor的空间。HotSpot默认Eden:Survivor=8:1.
  3. 标记-整理算法:和Mark-Swap一样,但最后复制后的存活对象向一端移动。
  4. 分代算法:新生代用复制算法,老年代用标记清理算法活着标记整理算法。

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值