JVM内存分配和垃圾收集策略
java内存区域
程序计数器
因为java可以多线程并发执行,因此,为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器。记录正在执行的虚拟机字节码指令的地址。
这个区域不会产生内存溢出异常。
栈
java虚拟机栈
栈中主要存放了编译期可知的四类八种基本数据类型存(逻辑型 boolean、文本型char、整数型byte、short、int、float、浮点数型double、long),对象引用类型,和对象引用类型(reference)。
本地方法栈
本地方法栈和java虚拟机栈所发挥的作用非常相似,他们之前的区别是虚拟机栈为虚拟机执行java方法服务。而本地方法栈是为虚拟机使用到的Native方法服务。
-Xss参数可以设置本地方法栈的内存上限。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
程序中 递归如果找不到出口也会抛出此异常(不断的进行入栈操作)
堆
用于存放对象的实列
可通过-Xms和Xmx来扩展堆的大小。因为现在的收集器基本都采用分代收集算法,所以java堆中还可以细分:新生代和老年代
如果在堆中没有内存完成实列分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。-Xmx可以设置堆内存的上限 -Xms 可以设置内存初始化的大小
方法区 PermGen space(也称永久代、也叫非堆 )
用于储存已被虚拟机加载的类的信息(编译后的class)、常量、静态变量、即时编译器编译后的代码等数据,Class在被Loader时就会被放到方法区中,加载类的类加载器本身也存在这里。
垃圾收集行为在这个区比较少出现的,有点类似它的名字,永久代
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError(后面会跟PermGen space字符串)异常。-XX:MaxPermSize可以设置方法区的上限。
运行时常量池(方法区的一部分)
用于存放编译期生成的各种字面量和符号的引用,既然运行时常量池是方法区的一部分,自然收到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
JAVA的String声明的变量就是放在运行时常量池中比如String str="test"; 。
但是 String str=new String("test");是new一个对象 是放在堆中(用new关键字创建字符串常量时,JVM会首先检查字符串常量池,如果字符串不存在常量池中,就会在实例化该字符串(堆中)的同时,在常量池也存放一份)
由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串
以上
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。可通过-Xmx和-XX:MaxPermSize可以设置堆内存和方法区上限。-Xmx2048m -XX:MaxPermSize=512m
把-Xmx 和-Xms大小设置一样内存大小,可以提高JVM的运行性能(取消掉伸缩区)
对象的finalize()方法简介
当垃圾回收器要释放无用对象的内存时,会先调用该对象的finalize()方法。对象的finalize()方法有以下特点
1)垃圾回收是否执行该方法,以及何时执行该方法都是不确定的。
换句话说 以下这种情况是有可能的:一个程序只占用了少量内存,没有造成严重的内存需求,于是垃圾回收器没有释放那些无用对象的内存,因此这些对象的finalize()方法还没有被调用,程序就终止了。
2)finalize()方法有可能使对象复活,使它恢复到可触及状态。
可触及状态:当一个对象 假定A对象被创建后,只要程序中还有引用变量在引用它,那么它就始终处于可触及状态。
可复活状态:当程序不在有任何变量引用A对象时,那么它就进入可复活状态。在这个状态中,垃圾回收期会准备释放它的内存,在释放之前,会调用其他处于可复活状态的finalize()方法,这些finalize()方法有可能使A对象重新转到可触及状态。
不可触及状态:当java虚拟机执行完所有可复活对象的finalize()方法后,假如这些方法都没有使A对象转到可触及状态,那么A对象就进入不可触及状态,垃圾回收才会真正的回收它的内存。
3)垃圾回收器在执行finalize()方法时,如果出现异常,垃圾回收器不会报告异常,程序继续正常执行。
判断对象是否需要回收
引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用他时,计数器值就加1;当引用失效时,计数器值就减一;任何时刻计数器为0的对象就是不可能在被使用的。
这种方法实现简单,判定效率也很高,但是主流的java虚拟机里面没有采用这种方法,因为它很难解决循环引用的问题。
可达性分析算法(主流的商业语言所采用的算法)
这个算法的基本思路就是通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(GC Roots到这个对象不可达)时,则证明此对象是不可用的。
在JAVA语言中,可作为GC Roots的对象包括以下几种:
- 虚拟机栈中引用的对象
- 方法区中类静态熟悉引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象
JVM垃圾收集算法
标记——清除算法
首先标记出所有需要回收的对象,在标记完成后统一回收。
缺点:这种回收算法会产生大量不连续的内存碎片。以后程序运行过程中产生较大的对象时,无法找到足够连续的内存 而不得不提前触发另一次垃圾收集动作。
复制算法
将内存按容量划分大小相等的两块,每次只使用一块。当这一块的内存用完了,就将还存活的对象复制到另外一块内存上面。
缺点:将内存的使用率缩小了一半
标记——整理算法
首先标记出所有需要回收的对象,然后让所有存活的对象都向一端移动。然后直接清理掉端边界以外的内存
分代收集算法
我们jdk采用的应该就是分代收集算法。根据对象存活周期的不同将内存划分为几块,针对每一块使用不同的算法
新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要对少量存活的对象复制就可以进行收集。
老年代中(新生代中经过多次垃圾回收仍然存活的对象,例如缓存对象),因为对象存货率高,没有额外空间对它进行分配担保,就需要使用 标记——整理或者标记——清除算法。
基于JVisualVM的可视化监控
jdk的安装目录bin文件下有jvisualvm.exe可执行文件。可以用来监控虚拟机的性能和故障处理。
这款JDK自带用来监控内存的可视化工具的详细使用,更新中。。。。。。
JVM内存分配和垃圾收集策略的更多相关文章
- 【007】【JVM——内存分配和恢复策略】
内存分配与收回策略 JVM的自己主动内存管理要自己主动化地解决两个问题:对象分配内存以及回收分配给对象的内存.回收内存前几篇已经讲了.如今说内存分配.对象的内存分配一般分配在堆内存中,也可能经过 ...
- JVM内存模型及垃圾收集策略解析(一)
JVM内存模型是Java的核心技术之一,之前51CTO曾为大家介绍过JVM分代垃圾回收策略的基础概念,现在很多编程语言都引入了类似Java JVM的内存模型和垃圾收集器的机制,下面我们将主要针对Jav ...
- JVM内存模型以及垃圾收集策略解析
http://xmuzyq.iteye.com/blog/599750 一 JVM内存模型 1.1 Java栈 Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程. ...
- JVM内存模型及垃圾收集策略解析
一 JVM内存模型 1.1 Java栈 Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程.它主要用来存储线程执行过程中的局部变量,方法的返回值,以及方法调用上下文 ...
- jvm内存分配和回收策略
在上一篇中,已经介绍了内存结构是什么样的. 这篇来介绍一下 内存是怎么分配的,和怎么回收的.(基本取自<深入理解Java虚拟机>一书) java技术体系中所提倡的自动内存管理最终可以归结为 ...
- JVM 内存分配和回收策略
对象的内存分配,主要是在java堆上分配(有可能经过JIT编译后被拆为标量类型并间接地在栈上分配),如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也是直接分配到老年代,分配规则不 ...
- A4. JVM 内存分配及回收策略
[概述] Java 技术体系中所提倡的自动内存管理最终可以归结为自动化地解决两个问题:给对象分配内存以及回收分配给对象的内存. 对象的内存分配,往大方向讲,就是在堆上分配,对象主要分配在新生代的 Ed ...
- JVM——内存分配与回收策略
1.对象优先在Eden区分配 大多数情况下,对象在新生代Eden区分配.当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC. 虚拟机提供了 -XX:+PrintGCDetails这 ...
- JVM内存分配与回收策略
对象优先在Eden分配 大多数情况下,对象在新生代Eden区中分配. 当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC. Minor GC:新生代GC,指发生在新生代的垃圾收集动作 ...
随机推荐
- 1.为什么使用spring boot
最近2年spring cloud微服务比较流行,Spring Cloud基于SpringBoot,为微服务体系开发中的架构问题提供了一整套的解决方案, 本文总结一下为什么要使用Spring boot, ...
- hbase-写操作
hbase连接过程 hbase client在写入的数据的过程中,是直接和rs进行通信的,整个的数据写入流程并不涉及到HMaster.那么client是如何找到对应的rs呢?流程如下: client从 ...
- 转 Java操作PDF之iText详细入门
转 Java操作PDF之iText详细入门 2016年08月08日 11:06:00 阅读数:19490 iText是著名的开放项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成 ...
- h5页面转图片长按保存
5页面经常会遇到此类需求.将最后的结果页转换为图片长按保存.下面介绍一下实现此需求的过程 1,依赖安装 cnpm install html2canvas --save 2,依赖引入,使用 绑定 初始化 ...
- yii2.0 邮件发送如何配置
邮件发送配置: 打开配置文件将下面代码添加到 components => [...]中(例:高级版默认配置在/common/config/main-local.php) 'mai ...
- mysql修改用户密码命令
C:\Users\20160216>mysql -h 10.180.6.183 -u root -pEnter password: ******Welcome to the MySQL moni ...
- Numpy 数据类型
numpy支持的数据类型比Python内置的类型多很多,基本上可以和C语言的数据类型对应上, 其中部分类型对应为Python内置的类型.下表列举了常用的Numpy基本类型. 名称 描述 bool_ 布 ...
- core的微服务相关
网关是ocelot consul 服务发现 配置中心apollo
- gperftools对程序进行分析
gperftools是google出品的一个性能分析工具,相关介绍可见:https://github.com/gperftools/gperftools/wikigperftools性能分析通过抽样方 ...
- Clinet/Server在工作线程中刷新页面数据的方法
Worker线程不能修改UI线程的状态(比如文本框里面的内容).解决的办法是写一个用来更新文本框内容的函数,然后在Worker线程里面通过BeginInvoke来利用delegate调用这个函数更新文 ...