Java JVM运行时数据区,内存管理和GC垃圾回收

一 . 运行时数据区
程序计数器是线程私有的,是一块很小的内存空间,是当前线程执行到字节码行号的计数指示器。每个CPU处理器核心 在任何一个时刻,都只可能运行着唯一的一个线程,执行着一条指令。所以在多线程的应用中,线程不断切换和分配时间片。在线程切换来切换去的过程中,就是靠程序计数器来了解,该如果继续恢复运行该线程。
虚拟机栈和Native方法栈也是线程私有的。在Sun HotSpot虚拟机中虚拟机栈和Native方法栈是被合二为一的。虚拟机栈描述的是Java方法执行的内存模型,栈帧用于存储局部变量表,方法出口等信息。每一个方法调用到执行完成都对应着一个栈帧在虚拟机栈中的入栈和出栈的过程。局部变量表中存放了八种基本数据类型和对象引用,还有returnAddress类型。前两种不难理解,returnAddress实际上是指向一条字节码指令的地址,局部变量表所需的内存空间在编译期间完成分配,当进入某个方法时,需要在栈帧中分配多大的局部空间是完全确定的,方法运行期间是不会改变局部变量表的大小。本地方法栈和虚拟机栈作用相似,虚拟机栈执行我们的java方法,本地方法栈就是执行Native方法,所以就是Native方法栈。简单地讲,一个Native Method就是一个java调用非java代码的接口。
Java堆是所有线程共享的区域,虚拟机管理的内存中最大的一块。基础所有对象的实例都是在这里分配内存。Java堆是GC的主要回收对象,虚拟机栈上局部变狼表所存的对象引用,就是指向堆内存中的一块地址。详细内容后面垃圾回收会提到更多。
方法区也是一块所有线程共享的区域,这里存储虚拟机加载的类信息,常量,静态变量,JIT编译后的代码等数据。运行时常量池是方法区的一部分。
接下来要说到JVM GC机制,在垃圾回收中堆内存上移动对象位置是很常见的, 所以对象的访问方式也要顺便提一下,也可以展示下方法区的类型是如何被引用的。我们都知道栈上的局部变量表中,有存储reference数据的引用,它可能是对象的直接地址,也可能是句柄地址。


由于对象访问极其频繁,所以Hot Spot也使用第二种方式,直接存实例引用是效率比较高的。但是第一种句柄的方式,好处在于,垃圾回收中,不需要更改栈上所存储的地址,栈上的存储稳定,只需要修改句柄池。
二.垃圾回收GC
说到垃圾回收 ,就不得不说垃圾回收算法的思想, 说到回收算法, 又不得不想到,什么样的对象需要被回收?什么是存活对象,什么对象已死亡。判断对象的存活与死亡,通常有两种方法,引用计数法和可达性分析算法。引用计数算法的问题在于,无法解决两个对象间相互引用的问题,导致不得达的对象依然无法回收。下面是实例:
A.b=B ; //这里 B 引用计数+1 A对象在堆上 其属性b存着B的引用
B.a=A ; // 与上方同理
A=null;
B=null; //A B两对象栈上引用 给null AB堆上实例做到不可达
//此时导致 AB对象实例内存不会被回收
所以为了解决这个问题,Java虚拟机中 使用可达性分析算法。其思想是从可作为GC Root根结点的对象,向下搜索,搜索过的路成为引用链,凡事不能达到的对象,认为是可回收对象。有几种对象可以作为GC Root对象。
1. 虚拟机栈上(栈帧的本地变量表)引用的对象。 2. 方法区中类静态属性引用的对象。 3. 方法区中常量引用的对象 4. 本地方法栈上Native方法引用的对象。
试想一下,为什么这些对象可以作为GC Root,为什么其他对象无法作为GC Root。 比如你的一个接口,处理请求的时候,有很多线程本地变量 , 但是 处理完请求后,这些对象就都没用了,所以他们一般不能作为GC Root。什么时候本地变量会成为GC Root呢? 个人的猜测应该是在GC大面积回收,程序暂停的时候, 这个时候,不能把当前正在运行的数据和变量清理掉呀。这时候提升为GC Root是很恰当的我觉得。至于静态属性,常量什么的作为GC Root毋庸置疑了,他们本来生命周期就是整个应用程序生命周期。
如何判断对象存活与死亡说过了,还需要了解的就是垃圾回收算法 。有四种思想需要提到, 其中有一种最基本的叫做 标记-清除算法。另外很重要的复制算法,是年轻代最合适的。还有一种标记整理算法,是老年代最合适的。最后一种就是分代这个思想。
标记清除就是首先对所有需要回收的对象进行标记,最后统一进行清除。这样的做法效率不高,清理后内存碎片很多,可能导致后期大对象无法分配内存,会经常触发另一次垃圾回收。
复制算法的思想是,将内存分为两块,其中一块保持为空,回收的时候,将存活的对象复制到空的一块,复制完成后,对原来那半内存全部清理。但是java虚拟机并不能留出一半的内存,这样太浪费资源,并且在Java堆中,年轻代里绝大部分内存都是要被回收的。所以Hot Spot中,将年轻代分为8:1:1的Eden,Survivor * 2, 就是一块Eden , 两块Survivor。 所以年轻代的策略,优先使用大的Eden,必须保持一块Survivor为空。回收的时候,将存活的对象,复制到空的Survivor内存区域,清理Eden和刚才使用的Survivor。
如果Survivor放不下存活的对象了,和时候 就该有对象进入老年代了~ 老年代使用标记—整理算法。标记整理思路就是,先标记,然后在回收的时候,将存活的对象移动到一端,将被清理的移动到另一端。然后清理端边界意外的内存。
Java JVM运行时数据区,内存管理和GC垃圾回收的更多相关文章
- Java内存管理:Java内存区域 JVM运行时数据区
转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...
- Java中的字符串常量池和JVM运行时数据区的相关概念
什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...
- JVM运行时数据区及对象在内存中初始化的过程
JVM运行时数据区 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter R ...
- JVM运行时数据区与JVM堆内存模型小结
前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...
- Jvm运行时数据区 —— Java虚拟机结构小记
关于jvm虚拟机的文章网上都讲烂了.尤其是jvm运行时数据区的内容. 抱着眼见为实的想法,自己翻了翻JVM规范,花了点时间稍微梳理了一下. 以下是阅读Java虚拟机规范(Java SE 8版)的第二章 ...
- JVM运行时数据区(二)
4.本地方法栈 本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务. 与Java虚拟机栈一样本地 ...
- Jvm运行时数据区
一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...
- JVM 运行时数据区 (三)
JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...
- JVM总结(一):概述--JVM运行时数据区
大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...
随机推荐
- C++中虚函数的作用是什么?它应该怎么用呢?
虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...
- 使用一层神经网络训练mnist数据集
import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_dat ...
- 设计模式之装饰模式(iOS开发,代码用Objective-C展示)
在面向对象编程中有个重要的原则,里氏代换原则:一个软件实体如果使用的是一个父类的话,那么一定适用其子类,而且它察觉不出父类对象与子类对象的区别.也就是说,在软件设计里面,把父类替换成它的子类,程序的行 ...
- php去除字符串中的HTML标签
php自带的函数可以去除/删除字符串中的HTML标签/代码. strip_tags(string,allow):函数剥去 HTML.XML 以及 PHP 的标签. 参数:string,必填,规定要检查 ...
- C#中的Partial
Partial关键词定义的类可以在多个地方被定义,最后编译的时候会被当作一个类来处理. 首先看一段在C#中经常出现的代码,界面和后台分离,但是类名相同. public partial class Fo ...
- 关于OpenVR
一直在期待一种大一统的开放的VR技术规范,虽然短期内这点明显是不太现实的.前几天在翻译Godot的开发进展#6那篇文章时,看到了一个词OpenVR,瞬间有感觉了. 从我的经历的技术规范演进版本来看,从 ...
- JMX超详细解读<转>
一.JMX的定义 JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架.JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和 ...
- AT24Cxx(EEPROM)子系统
1.配置内核 打开I2C功能: 打开杂项设备,该选项打开后,EEPROM也就打开了. 2. 修改代码 修改文件: linux/arch/arm/mach-s3c2440/mach-smdk2440.c ...
- android 技术点记录
Android Service完全解析,关于服务你所需知道的一切(上) http://blog.csdn.net/guolin_blog/article/details/11952435 androi ...
- CAS (11) —— CAS TicketRegistry使用Ehcache的集群方案
CAS (11) -- CAS TicketRegistry使用Ehcache的集群方案 摘要 CAS TicketRegistry使用Ehcache的集群方案 版本 tomcat版本: tomcat ...