上一篇文章中讨论了Java内存运行时的各个区域,其中程序计数器、虚拟机栈、本地方法栈随线程生灭,且创建时需要多少内存,基本上在译期间就决定的了,所以在内存回收时无需特殊的关注。而堆和方法区则不同,首先堆中只能在运行时,随着方法的调用而确定创建哪些对象;方法区中也同样如此,常量池中的常量、加载的类信息也是随时在发生着变化且不可预知。所以说,JVM内存回收,主要针对的是这两部分的内容。

1、堆中“死”对象

  笼统的说,没用的对象就是死对象。

1.1如何判定对象“已死”

1.1.1引用计数法

  给对象添加一个引用计数器,当有其他对象引用该对象时,计数器+1;当引用失效时,计数器-1。原理简单,实现容易,听起来也不错。但这个算法无法解决对象间循环引用的问题。也就是说对象A引用了对象B,而对象B同时也引用了对象A,此时就形成了循环引用。这样两个对象就永远都不会被回收。主流的JVM中均没有采用这种算法。

1.1.2可达性分析

  基本思路是找一些对象作为遍历的起始点(成为GC Roots),从这些起始点开始搜索,当某个对象并没有和任何GC Root产生关联,则认为这个对象已经不被使用了,可以清除。通常,可作为GC Root的对象有以下几种:

    1)虚拟机栈,栈帧中的本地变量表中引用的对象

    2)方法区中加载的类的静态属性引用的对象

    3)方法区中常量引用的对象(疑问,方法区中的常量到底有哪些)

    4)本地方法栈中引用的对象

  由上可见,可作为GC Roots的对象基本上可以归类为全局性引用和执行上下文,而应用中这些对象实在太多,这就导致根节点的遍历(或者叫确定GC Roots)势必会消耗很多时间,那是如何确定GC Roots的呢?当前主流Java虚拟机使用的都是准确式GC,以HotSpot虚拟机为例,当系统确定GC Roots时,并不需要遍历整个方法区或者堆,而是知道哪些地方存放着对象的引用,这是有一个叫OopMap的数据结构来实现的。

1.2关于引用

  上文谈到的引用,是我们平时经常谈到的、最直白的“引用”。在JDK1.2之前,“引用”的定义是:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。这种定义非常的纯粹,非黑即白。在内存回收的时候也是,有用就留着,没用立刻删。但有一些场景,例如,当内存充足的时候,某块内存留着备用;内存不充足的时候,回收这块内存。这时纯粹的“引用”就没办法了。在JDK1.2之后,Java对引用进行了扩展,将引用分为强引用、软引用、弱引用、虚引用。

  1)强引用:就是上面说的纯粹的引用

String str=new String("abc"); 

  2)软引用:表示对象还有用,但不是必须的。内存不够用的时候,才会回收这些内存。软引用可用来实现内存敏感的高速缓存。

String str=new String("abc");                                     // 强引用
SoftReference<String> softRef=new SoftReference<String>(str); // 软引用

后续在垃圾回收时,JVM内部逻辑如下:

if(JVM.内存不足()) {
str = null; // 转换为软引用
System.gc(); // 垃圾回收器进行回收
}

  3)弱引用:表示对象还有用,但不是必须的,且不如软引用“硬”。只要发生垃圾回收,这些对象就会被回收。

String str=new String("abc");
WeakReference<String> weakRef = new WeakReference<String>(str);

后续在垃圾回收时,JVM内部逻辑如下:

str = null;

  4)虚引用:最弱的引用,一个对象是否存在虚引用,并不影响其生存。为一个对象设置虚引用的唯一目的是在该对象被回收时,能够收到一个系统通知。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。

2、方法区内内存

  JDK1.8之前方法区是放到永久代中实现的(HotSpot虚拟机)。对于堆中的内存回收,尤其是新生代,回收率能够达到70%~95%;而永久代中的回收率则非常低。也就是说,回收方法区内的内存性价比很低。但这块内存又不能没有垃圾回收机制,SUN公司就曾公布过关于方法区内存泄漏的严重BUG。

  方法区中垃圾回收主要关注两部分:无用的常量和类。

  常量的回收与堆中对象的回收机制类似,当某个常量没有被任何对象引用的时候,这个常量就没有用了,就可以被回收。举例,当前系统中找不到任何String对象引用了常量池中的的某个字符串常量:abcd,那么abcd这个常量就会被回收。同理,常量池中其他类、方法、字段的符号引用也与此类似。

  回收类的效率非常低,但在当前企业级应用大量使用反射(Spring IOC,在bean注入的时候,通过反射实例化一个类,将其通过setter方法放到bean中)、动态代理(Spring AOP,AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。)、CGLib(CGLib技术后续继续学习)等技术的前提下,类的回收也变得很重要。已加载类的回收条件非常苛刻,需要满足以下三个条件,才有可能被JVM回收:

    1)该类产生的对象实例均被回收

    2)加载该类的ClassLoader已经被回收(类加载机制后续继续学习)

    3)该类的类对象没有在任何地方引用,无法反射出这个类的方法

JVM内存回收机制——哪些内存需要被回收(JVM学习系列2)的更多相关文章

  1. JVM自动内存管理机制——Java内存区域(下)

    一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...

  2. Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 一.前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存.垃圾 ...

  3. JS基础-垃圾回收机制与内存泄漏的优化

    [V8引擎]浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略 垃圾回收机制 如何判断回收内容 如何确定哪些内存需要回收,哪些内存不需要回收,这是垃圾回收期需要解决的最基本问题.我们可以这样 ...

  4. Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制

    Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches   Slab内存管理机制 SLUB内存管理机制 http://w ...

  5. GNU C - 关于8086的内存访问机制以及内存对齐(memory alignment)

    一.为什么需要内存对齐? 无论做什么事情,我都习惯性的问自己:为什么我要去做这件事情? 是啊,这可能也是个大家都会去想的问题, 因为我们都不能稀里糊涂的或者.那为什么需要内存对齐呢?这要从cpu的内存 ...

  6. JVM和GC垃圾回收机制和内存分配

    JVM运行期间 线程共享 线程私有 线程共享: 方法区 堆方法区:存放可以共享数据,静态常量,类的共有方法属性字段等,可以共享的存在方法区. 堆:存放class对象 . 线程私有:本地方法栈 虚拟机栈 ...

  7. JVM垃圾回收机制与内存回收

    暂时转于:https://blog.csdn.net/qq_27035123/article/details/72857739 垃圾回收机制 GC是垃圾回收机制,java中将内存管理交给垃圾回收机制, ...

  8. Java垃圾回收机制以及内存泄露

    1.Java的内存泄露介绍 首先明白一下内存泄露的概念:内存泄露是指程序执行过程动态分配了内存,可是在程序结束的时候这块内存没有被释放,从而导致这块内存不可用,这就是内存 泄露,重新启动计算机能够解决 ...

  9. JVM自动内存管理机制——Java内存区域(上)

    一.JVM运行时数据区域概述 Java相比较于C/C++的一个特点就是,在虚拟机自动内存管理机制的帮助下,我们不需要为每一个操作都写像C/C++一样的delete/free代码,所以也不容易出现内存泄 ...

随机推荐

  1. HTML入门6

    这篇将简单会编写网页整体网站架构,通过HTML来表示网站结构. 标题<header>,通常顶部有个大标题或图标,是网站的主要常见信息,存在于每个网页 导航<nav>,通常包含菜 ...

  2. ERP项目实施记录11-产品工艺流程图及单据关联图

    借助百度的Echarts做了2个图表,一个展示产品的生产工艺流程,一个展示产品与订单.工程单的关系 上图为产品工艺流程图,鼠标放上去可以显示部件信息 黄色SO图标代表销售订单,单击打开销售订单 红色M ...

  3. 英特尔神经棒使用入门-NCS2 & NCS1 -OpenVino

    |--背景: NCS1使用的NCSDK1和NCSDK2,速度一般,没有想象中的速度,能有TX2一半的速度吧.跟大佬又申请了个NCS2来试一试. 环境配置到跑通自己写的MNIST分类网络花了2天不到吧. ...

  4. 织梦手机站下一篇变上一篇而且还出错Request Error!

    最新的织梦dedecms程序手机版下一篇变上一篇而且还出错Request Error!,这是因为官方写错了一个地方 打开 /include/arc.archives.class.php 找到 $mli ...

  5. bootstrap-treeview分级展示列表树的实现

    html页面: 要引用 "/webapp/common/css/bootstrap-treeview.css" "/webapp/common/js/bootstrap- ...

  6. Js中Map对象的使用

    Js中Map对象的使用 1.定义 键/值对的集合. 2.语法 mapObj = new Map() 3.备注 集合中的键和值可以是任何类型.如果使用现有密钥向集合添加值,则新值会替换旧值. 4.属性 ...

  7. docsis cm 上线过程(bigwhite)

    扫描与同步下行(SYNC消息) 获取上行参数(UCD消息.MAP消息)  通过测距完成时间偏移等的调整(RNG消息) 设备类型鉴定(可选,DCI消息) 建立IP通道(DHCP)  同步系统时间(TOD ...

  8. Python 学习笔记2 变量

    Python变量的一些命名规则和指南 每种编程语言都需要变量, 这些变量的命名,我们一般会遵守一些公认的规则. 已达到方便自己,他人阅读的好处. 变量只能包含字母.数字和下划线.变量可以以字母和下划线 ...

  9. 洛谷P4640 王之财宝 [BJWC2008] 数论

    正解:容斥+Lucas+组合数学 解题报告: 传送门! 和上一篇题解的题差不多,,,双倍经验趴大概算 还是说下还是有点儿区别的来着$QwQ$ 两个小差别分别港下$QwQ$ 首先有$m-n$件是无穷个的 ...

  10. centos7 + php7

    安装php7 https://www.zntec.cn/archives/centos7-lamp.html composer安装tp curl -sS https://getcomposer.org ...