java gc机制新区域旧屋_Java 内存回收机制——GC机制-Go语言中文社区

一、Java GC 概念说明

Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,防止出现内存泄露和溢出问题。

Java GC机制主要完成3件事:确定哪些内存需要回收,确定什么时候需要执行GC,如何执行GC。下面我们将从4个方面学习Java GC机制,1,内存是如何分配的;2,如何保证内存不被错误回收(即:哪些内存需要回收);3,在什么情况下执行GC以及执行GC的方式;4,如何监控和优化GC机制。

二、Java内存区域划分

了解Java GC机制,必须先清楚在JVM中内存区域的划分。在Java运行时的数据区里,由JVM管理的内存区域分为下图几个模块:

837a88465abe5ae15882c22792251115.png

1. 程序计数器(Program Counter Register)

程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。

每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。

如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是一个本地(native,由C语言编写完成)方法,则计数器的值为Undefined,由于程序计数器只是记录当前指令地址,所以不存在内存溢出的情况,因此,程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。

2. Java虚拟机栈(Java Virtual Machine Stacks)

一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame),栈帧中存储的有局部变量表、操作站、动态链接、方法出口等,当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈。

局部变量表中存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等。在局部变量表中,只有long和double类型会占用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。

虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足,此时,会抛出OutOfMemoryError(内存溢出)。

每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的。

3. 本地方法栈(Native Method Stacks)

本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。

本地方法栈也是线程私有的。

4. 堆区(Heap) (新生代和旧生代)

堆区是理解Java GC机制最重要的区域,没有之一。在JVM所管理的内存中,堆区是最大的一块,堆区也是Java GC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区的存在是为了存储对象实例,原则上讲,所有的对象都在堆区上分配内存(不过现代技术里,也不是这么绝对的,也有栈上直接分配的)。

一般的,根据Java虚拟机规范规定,堆内存需要在逻辑上是连续的(在物理上不需要),在实现时,可以是固定大小的,也可以是可扩展的,目前主流的虚拟机都是可扩展的。如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java heap space异常。

5. 方法区(Method Area)(永久代)

方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。

方法区在物理上也不需要是连续的,可以选择固定大小或可扩展大小,并且方法区比堆还多了一个限制:可以选择是否执行垃圾收集。一般的,方法区上执行的垃圾收集是很少的。但这也不代表着在方法区上完全没有垃圾收集,其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。

在方法区上进行垃圾收集,条件苛刻而且相当困难,效果也不令人满意,所以一般不做太多考虑,可以留作以后进一步深入研究时使用。

在方法区上定义了OutOfMemoryError:PermGen space异常,在内存不足时抛出。

6. 新生代、旧生代、永久代

虚拟机中共划分为三个代:新生代、旧生代、永久代。年轻代和年老代的划分是对垃圾收集影响比较大的。

所有新生成的对象首先都是放在新生代的;旧生代中存放的都是一些生命周期较长的对象。永久代用于存放静态文件,如Java类、方法等。永久代对垃圾回收没有显著影响。

三、Java对象的访问方式

一个Java的引用访问涉及到3个内存区域:JVM栈,堆,方法区。

以最简单的本地变量引用:Object obj = new Object()为例:

Object obj表示一个本地引用,存储在JVM栈的本地变量表中,表示一个reference类型数据;

new Object()作为实例对象数据存储在堆中;

堆中还记录了Object类的类型信息(接口、方法、field、对象类型等)的地址,这些地址所执行的数据存储在方法区中;

在Java虚拟机规范中,对于通过reference类型引用访问具体对象的方式并未做规定,目前主流的实现方式主要有两种:

1. 通过句柄访问:

879a2d33ec1896339a59239b539ad0eb.png

通过句柄访问的实现方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分稳定。

2. 通过直接指针访问:

06c4944196863ac1e506b48d367a5e2d.png

通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。

四、参考资料

1.《JAVA编程思想》第5章

2.《Java深度历险》Java垃圾回收机制与引用类型

3.《深入理解Java虚拟机:JVM高级特效与最佳实现》,第2-3章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/528557.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上古卷轴5java8_【图片】【上古卷轴5】【无心】个人整合版8.0【霜刃伤情吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼GameModeSkyrimSkyrim.esm1Update.esm1Unofficial Skyrim Patch.esp1Dawnguard.esm1Unofficial Dawnguard Patch.esp1HearthFires.esm1Unofficial Hearthfire Patch.esp1Dragonborn.esm1Unofficial Dragonborn Patch.esp1Skyrim Pr…

java反射 虚拟机优化_面试官问我:Java反射是什么?我回答竟然不上来......

每天凌晨00点00分,第一时间与你相约每日英文We all have moments of desperation. But if we can face them head on, that’s when we find out just how strong we really are.我们都有绝望的时候,只有在勇敢面对时,我们才知道我们有多坚强。每日掏心话…

mysql解压包安装linuex_CentOS下安装Apache,php,Mysql

第一步:通过yum安装php,mysql,httpd,这里默认使用CentOS提供的默认版本,版本较低。#yum install httpd mysql-server php php-devel php-mysql所有的安装包大小为25M,大概2分钟左右就能下载安装完成。第二步…

c java 开发效率高_Java 的开发效率究竟比 C++ 高在哪里?

如果选择C,那C 的难度与JAVA 比,那应该不在一个层次。因为 C 作者及委员会想给你带来足够的抽象能力,让你可以抽象这个世界;给你足够的自由与控制硬件的能力,及零开销的高性能。简单点说,C程序员如同神一般…

java sub,Java 9子软件包跨模块拆分

In Java 9, can I split sub-packages across modules? For example, can I have com.example.foo in one module and com.example.foo.bar in another module?This seems like a simple question, but for some reason Im not able to find a direct answer after some sear…

java矩阵类_151-矩阵类

[java]代码库import java.util.Scanner;import java.util.Arrays;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);int r scan.nextInt();int c scan.nextInt();System.out.println("row:"r" column:"…

python3 for sum_Python for循环和“sum13”方法

我是一个刚开始学习Python的本地C程序员,我已经给出了以下的写作方法:Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately …

java调用c jni_Java调用C JNI

JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在W…

java websphere mq_如何在java中使用WebSphere MQ?

Java中使用websphere websphere mq:用于传输信息 具有跨平台的功能。1 安装websphere mq并启动2 websphere mq建立queue Manager(如:MQSI_SAMPLE_QM)3 建立queue类型选择Local类型的(如lq)4 建立channels类型选择Server Connection(如BridgeChannel)以下…

java 序列化保存_保存到二进制/序列化Java

我必须报价,1.将帐户保存到二进制(序列化)文件中。2.从二进制(序列化)文件加载(重新创建)帐户。因此,首先,我正在查找确切的例子,而我却迷失了自己,在同样的情况下,人们提到xml,在我的脑海中&am…

java控制excel_java操作excel

1. 生成并下载excel文件controllerRequestMapping(value "/download", method RequestMethod.GET)public xxx downloadFile(HttpServletResponse response) {response.setContentType("application/octet-stream");response.setHeader("content-typ…

java 方法权限_Java控制访问权限的方法

这篇博客主要用来介绍Java中的访问权限.引入访问控制权限我们都知道,一个通用类库(如:JDK)开发出来的目的是让普通开发者重用以节省开发时间与精力,但是类库的设计不可能在刚开始就尽善尽美,普通开发者在对类库的使用过程中&#…

java套接字客户端_使用Java从客户端套接字读取数据(Read data from a client socket in Java)...

使用Java从客户端套接字读取数据(Read data from a client socket in Java)我编写了从客户端套接字发送/接收数据的代码。 发送数据步骤已成功完成,但是当我想从套接字读取数据时, readLine()方法阻止程序,而没有要读取的数据。这是我的代码&…

xml动态生成java_从XML文档动态生成Java类

考虑这种情况:我有一个名为person.xml的XML文件,其中包含以下数据.MrFoo28如果我想将这个XML读入Java对象,我将创建一个名为PersonBean的Java bean(使用属性的getter / setter):class Person{String name;int age;}我可以使用任何API来读取XML并填充Java…

java lpad oracle_Oracal的Lpad函数

2007-09-21 17:13 | pinty回复楼上,根据LEVEL的数决定输出“-”的个数,看下面的例子SELECT LEVEL, LPAD( ,2*(LEVEL - 1)) || lname "EMPLOYEE",emp_id, manager_emp_idFROM employeeSTART WITH emp_id 7839CONNECT BY NOCYCLE PRIOR emp_id …

用java输入学生姓名查询成绩_编写一个Java程序,提示用户输入学生数量,学生姓名和他们的成绩,并按照成绩的降序打印学生姓名...

importjava.util.Scanner;publicclassmyclass{publicstaticvoidmain(String[]args){ScannerinputnewScanner(System.in);System.out.print("请输入学生个数,学生姓名以及学生成绩");...import java.util.Scanner;public class myclass{public static void…

java对xml解析_Java中对xml的解析

// 1.通过DocumentBuilderFactor创建解析工厂DocumentBuilderFactory builderFactory DocumentBuilderFactory.newInstance();// 2.通过工厂获得解析器DocumentBuilder builder builderFactory.newDocumentBuilder();// 3.通过parser方法获取DocumentDocument document buil…

刻画小狗状态java_JAVA面向接口编程

JAVA面向接口编程小狗在不同环境条件下可能呈现不同的状态,小狗通过调用 cry()方法体现自己的当前的状 态。要求用接口封装小狗的状态。具体要求如下。• 编写一个接口 DogState,该接口有一个名字为 void showState()的方法。• 编写 Dog 类,…

java jdbc(mysql)驱动源码分析_JAVA JDBC(MySQL)驱动源码分析(二)

本文系转载,地址:http://blog.csdn.net/brilliancezhou/article/details/5425687上一篇中分析了Class.forName(“com.mysql.jdbc.Driver”)幕后所做的事情,也就是在Driver实现类中的静态块和构造函数,本篇主要来分析一下静态块的一…

java %3c%=a%%3e_跪求帮忙解析,急!!!

xml 这个参数的值,是被 urlencode 两次的东西。 php 不懂, Python 的话是用 urllib.unquote 就可以了。>>> s %3C%3Fxmlversion%3D%221.0%22encoding%3D%22gbk%22%3F%3E%253Ctask%253E%253Cuser%253E%253Coper%253Emod%253C%252Foper%253E%253…