首先我们先来了解一下JVM内存模型,看看我们平时的类、方法和变量存放的区域。
1.JVM内存模型
(1)程序计数器
这里记录了线程执行的字节码的行号,在分支、循环、跳转、异常、线程恢复等都依赖这个计数器。
(2)java虚拟机堆
用来存放由new创建的对象和数组,在堆中分配空间,由Java虚拟机自动垃圾回收器管理。
(3)java虚拟机栈
在函数定义的一些基本类型变量和对象引用变量都是在栈中内存中分配的,当超过变量的作用域后,Java会自动释放为该变量的内存空间。
(4)方法区
方法区是系统分配的一个内存逻辑区域,是jvm在装载类文件是,用于存储信息的,如:类型信息、字段信息、方法信息、其他信息。
2.伟大的环卫工人(jvm自动垃圾回收器)
(1)为什么伟大?
c语言需要手动释放内存空间,java虚拟机定时自动回收。
(2)如何发现垃圾
1.程序计数器,如果发现虚拟机栈变量或类被引用,计数器会+1,相反未被引用计数器会-1,并定时对未引用的对象进行垃圾回收。
2.根搜索算法
栈帧里的局部变量所引用的对象,方法区的静态变量和常量所引用的对象;如果他们的根进程是可达的不会进行回收,如果不可达将会被回收。
3.jvm垃圾回收算法
1.标记清除算法
标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。在标记阶段首先通过根节点,标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。标记清除算法带来的一个问题是会存在大量的空间碎片,因为回收后的空间是不连续的,这样给大对象分配内存的时候可能会提前触发full gc。
2.分段复制算法
将现有的内存空间分为两快,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
3.标记整理算法
结合了以上两个算法,为了避免缺陷而提出。标记阶段和Mark-Sweep算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象
4.分带收集算法
分代收集法是目前大部分JVM所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将GC堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。
高效代码的技巧
内存泄漏
系统的代码非常多或引用的第三方包非常多、或代码中使用了大量的常量、或通过intern注入常量、或者通过动态代码加载等方法,导致常量池的膨胀,虽然JDK 1.5以后可以通过设置对永久带进行回收,但是我们希望的是这个地方是不做GC的,它够用就行,所以一般情况下今年少做类似的操作,所以在面对这种情况常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。
干掉JVM
本人对Java虚拟机理解刚刚入门,还在学习阶段,有些内容为网上借鉴。