JVM内存回收机制——哪些内存需要被回收(JVM学习系列2)
上一篇文章中讨论了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)的更多相关文章
- JVM自动内存管理机制——Java内存区域(下)
一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...
- Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略
V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 一.前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存.垃圾 ...
- JS基础-垃圾回收机制与内存泄漏的优化
[V8引擎]浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略 垃圾回收机制 如何判断回收内容 如何确定哪些内存需要回收,哪些内存不需要回收,这是垃圾回收期需要解决的最基本问题.我们可以这样 ...
- 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 ...
- GNU C - 关于8086的内存访问机制以及内存对齐(memory alignment)
一.为什么需要内存对齐? 无论做什么事情,我都习惯性的问自己:为什么我要去做这件事情? 是啊,这可能也是个大家都会去想的问题, 因为我们都不能稀里糊涂的或者.那为什么需要内存对齐呢?这要从cpu的内存 ...
- JVM和GC垃圾回收机制和内存分配
JVM运行期间 线程共享 线程私有 线程共享: 方法区 堆方法区:存放可以共享数据,静态常量,类的共有方法属性字段等,可以共享的存在方法区. 堆:存放class对象 . 线程私有:本地方法栈 虚拟机栈 ...
- JVM垃圾回收机制与内存回收
暂时转于:https://blog.csdn.net/qq_27035123/article/details/72857739 垃圾回收机制 GC是垃圾回收机制,java中将内存管理交给垃圾回收机制, ...
- Java垃圾回收机制以及内存泄露
1.Java的内存泄露介绍 首先明白一下内存泄露的概念:内存泄露是指程序执行过程动态分配了内存,可是在程序结束的时候这块内存没有被释放,从而导致这块内存不可用,这就是内存 泄露,重新启动计算机能够解决 ...
- JVM自动内存管理机制——Java内存区域(上)
一.JVM运行时数据区域概述 Java相比较于C/C++的一个特点就是,在虚拟机自动内存管理机制的帮助下,我们不需要为每一个操作都写像C/C++一样的delete/free代码,所以也不容易出现内存泄 ...
随机推荐
- 找出数组[1...n]中第k小元素
//问题描述: 试编写一个算法,使之能够在数组L[1...n]中找出第k小的元素(即从小到大排序后处于第k个位置的元素) #include <stdio.h> // 结合快排思想,查找第5 ...
- 有关svn的报错
由于目标计算机积极拒绝,无法连接.当报出这样的错的时候就是跨域的问题
- JavaScript 特效之四大家族(offset/scroll/client/event)
三大系列:offset.scroll.client 事件对象:event(事件被触动时,鼠标和键盘的状态)(通过属性控制) 三大系列都是以DOM元素节点的属性形式存在的. 类比访问关系,也是以 ...
- Oracle 索引 index
索引是一个模式对象,其中包含每个值的条目,该条目出现在表或集群的索引列中,并提供对行的直接快速访问. 创建一个索引: create index 索引名 on 表名 (字段名); 删除索引: dro ...
- QQ设置手机和pc qq群消息不同步
作为开发人员QQ群很多,很正常,工作的时候才需要看qq信息和群消息,但是蛋疼qq在新版的qq必须设置同步,之前用的qq8.1版本可以设置不同步,但是现在突然不行 目前可以用的途径就是 QQ国际PC版2 ...
- Codeforces 1154F - Shovels Shop - [DP]
题目链接:https://codeforces.com/contest/1154/problem/F 题解: 首先,可以确定的是: 1.$(x,y)$ 里 $x>k$ 的都不可能用: 2.肯定买 ...
- Mysqlutil.JDBCutil.Dtabaseutil数据库操作工具类[批量操作]
一个用来操作数据库的常用工具类. 提供批量操作,生成建表,插入语句等 操作示例: // 1.获取连接 DataBaseUtil jdbc = new DataBaseUtil(); jdbc.getC ...
- 使用vue实现tab栏的点击切换样式
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- 关于php得到参数数据
通过GET得到参数数据 $_SERVER['QUERY_STRING'] 获取?后面的值 $_SERVER['SCRIPT_NAME'] 获取当前脚本的路径 具体参数通过_GET['参数']获得 fi ...
- 设计、定义并实现Complex类
设计.定义并实现Complex类 #include <iostream> #include <cmath> using namespace std; class MyCompl ...