Java内存区域与内存溢出异常——深入理解Java虚拟机 笔记一

时间:2022-09-06 19:43:38

Java内存区域

  对比与C和C++,Java程序员不需要时时刻刻在意对象的创建和删除过程造成的内存溢出、内存泄露等问题,Java虚拟机很好地帮助我们解决了内存管理的问题,但深入理解Java内存区域,有助于帮我们理解Java虚拟机到底是如何解决内存问题,如果出现了内存泄露或内存溢出等方面的问题,我们也可以找到问题的解决方案。

Java内存区域划分

   Java虚拟机在执行Java程序的过程中,会把它管理的内存划分成若干个数据区域。有的区域随着虚拟机进程启动而存在,有的区域则是依赖用户线程的启动和结束而建立和销毁,Java运行时数据区的划分如下图,方法区和堆属于所有线程共享的数据区,而虚拟机栈、本地方法栈、程序计数器则是每个线程有一个。而执行引擎将会在后面的章节介绍。

Java内存区域与内存溢出异常——深入理解Java虚拟机  笔记一

程序计数器

   程序计数器,可以看做是当前线程执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条要执行的字节码指令,分支、循环、跳转等基础功能都依赖于此计数器完成。

   关于字节码:字节码是我们写好java源代码以后,经过编译生成的可以使JVM读懂的语言。比如我们编译后得到的.class文件。

   我们写好的java源码最终变成可执行文件的过程是:java源码-->经编译器生成的可执行java字节码(比如虚拟指令或者.class文件)-->经过JVM解释器变成机器可以执行的二进制文件-->程序运行。

   由于Java虚拟机的多线程是通过线程轮流切换并且分配处理器执行时间的方式来实现的,因此同一时间对于一个处理器而言,只有一个线程中的一条指令会被执行,因此,为了切换线程后,不同线程可以恢复到正常的位置,程序计数器是每个线程含有一个。他们之间互不影响,独立存储。

   如果执行的是Java方法,那么计数器记录的是正在执行的虚拟机字节码指令的地址,如果执行的是Native方法,那么计数器为空,此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError的区域。

Java虚拟机栈

   Java虚拟机栈的生命周期与线程相同,每个方法执行的时候会创建一个栈帧,用于存放局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。

   局部变量表存放了编译期可知的各种基本数据类型(boolen、byte、char、short、int、float、long、double)、对象引用(reference)和returnAddress类型(指向了一条字节码指令的地址).局部变量表所需的内存空间在编译期间完成非配,方法运行期间不会改变局部变量表的大小。

   我的理解是,对于在方法执行中,New新的对象、增加数组等,其本身是在堆上申请空间,然后返回一个引用存储在对应方法的栈中,因此局部变量表其大小在编译器就可以确定。

本地方法栈

   本地方法栈与虚拟机栈作用基本一致,只不过虚拟机栈为执行Java方法服务,而本地方法栈是为调用的Native服务。

Java堆

   Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例,Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续即可。

方法区

   方法区也是各个线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码

运行时常量池

   运行时常量池,是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池,用于存放编译期生成的各种字面量和符号引用

对象访问

   关于对象访问的问题,我们来看一个很典型的例子:

   Object obj = new Object();

   这一个简单的对象创建,实际涉及到了Java栈、Java堆、方法区三个区域的关联关系。

   首先对于Object obj而言,这在每个线程单独的虚拟机栈里创建了一个reference类型变量,指向Java堆中的一个地址,在Java堆中,存放的是new Object()新创建出来的实例数据值的结构化内存,而在方法区,则会创建该对象的类型、父类、接口、方法等地址信息。

   而实现reference类型指向对象的引用,有两种方法进行实现:句柄方法和直接指针

   如果使用句柄方法,在Java堆中将会划分出一块内存作为句柄池。java栈中的reference中存放的是的对象的句柄地址,句柄中包含了对象实例数据和类型数据各自的具体地址信息。

Java内存区域与内存溢出异常——深入理解Java虚拟机  笔记一

   如果使用指针访问方法,Java堆对象就必须考虑如何放置访问类型数据的相关信息,reference中存放的就是对象地址。

Java内存区域与内存溢出异常——深入理解Java虚拟机  笔记一

   使用句柄的好处是,reference存储的地址是稳定的句柄地址,就算对象因为垃圾回收机制而被移动(是很正常的事情),也只需要Java堆里的实例数据地址进行修改即可,在栈里的reference地址不需要改变。

   而使用直接指针访问的方式,就是速度快,reference存储的地址就是对象所在地址,节省了一次指针定位的开销。但缺点就是,如果对象在堆里发生了改变,那么在栈中的reference指向内容也要改变。

   

实际问题处理

堆溢出

   堆溢出的问题,重点是确认内存中对象是否是必要的,也就是检查是否有内存泄露问题。是否有对象已经不再需要使用,但仍然无法被垃圾回收机制收集。如果没有这样的对象,那么就应当检查虚拟机的堆参数是否合适、能否再扩大等问题。

栈溢出

   在多线程中,可能是产生的线程过多,从而导致每个线程可支配的内存容量变小,导致OutOfMemory的问题。也可能是同一个线程中执行内容栈帧过大,导致*Error的问题。

Java内存区域与内存溢出异常——深入理解Java虚拟机 笔记一的更多相关文章

  1. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  2. 《深入理解Java虚拟机》-----第2章 Java内存区域与内存溢出异常

    2.1 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任 ...

  3. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  4. 深入了解Java虚拟机(1)java内存区域与内存溢出异常

    java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...

  5. 第2章—Java内存区域与内存溢出异常

    2.1 概述 总结:本章将从概念上介绍 Java 虚拟机内存的各个区域,讲解这些区域的作用.服务对象以及其中可能产生的问题. 2.2 运行时数据区域 Java 虚拟机在执行 Java 程序的过程中会把 ...

  6. JVM高级特性与实践(一):Java内存区域 与 内存溢出异常

    套用<围城>中的一句话,“墙外面的人想进去,墙里面的人想出来”,用此来形容Java与C++之间这堵内存动态分配和垃圾收集技术所围成的“围墙”就再合适不过了. 对于从事C.C++的开发人员而 ...

  7. 深入理解java虚拟机----&gt&semi;java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  8. 第二章Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...

  9. 2&period;1 自动内存管理机制--Java内存区域与内存溢出异常

    自动内存管理机制 第二章.Java内存区域与内存溢出异常 [虚拟机中内存如何划分,以及哪部分区域.什么样代码和操作会导致内存溢出.各区域内存溢出的原因] 一.运行时数据区域 Java虚拟机所管理的内存 ...

随机推荐

  1. iOS 里面 NSTimer 防止 循环引用

    使用NSTimer的类 #import "TBTimerTestObject.h" #import "TBWeakTimerTarget.h" @interfa ...

  2. &lpar;转&rpar;Singleton 单例模式(懒汉方式和饿汉方式)

    原文地址:http://www.cnblogs.com/kkgreen/archive/2011/09/05/2166868.html 单例模式的概念: 单例模式的意思就是只有一个实例.单例模式确保某 ...

  3. qt-5&period;6&period;0 移植之纯净的linux文件系统的建立

    为什么要建立一个最纯净的文件系统,一开始是想在qt-4.8.5的文件系统基础之上加东西,慎重想了一下,这方法行不通,以为有很多东西不熟悉.干脆就自己建立一个. 步骤很简单: 一:下载一个bulidro ...

  4. &lbrack;Aaronyang&rsqb; 写给自己的WPF4&period;5 失传的第十本秘籍4&lbrack;wpf使用FontAwesome,并送其他3招心法&rsqb;

    总有一个人他教会你成长,然后又独自离开--Aaronyang的博客(www.ayjs.net)-www.8mi.me =============时隔两年后再看WPF,有些秘籍不太适合公开,公开了就不值 ...

  5. 最近用到的Linux常用命令总结

    最近用到的Linux常用命令总结 - ls :显示当前目录文件信息 `ls -a -l` - cd :目录跳转 cd .. 上级目录 cd ~ home目录 cd - 最近目录 - cat :在屏幕上 ...

  6. AndroidListview 滑动过程中图片显示重复错乱解决方案

    主要分析Android中Listview滚动过程造成的图片显示重复.错乱.闪烁的原因及解决方法,顺便跟进Listview的缓存机制. 1.原因分析 Listview item 缓存机制:为了使得性能更 ...

  7. kubernets 概念

    理解 Kubernetes 对象 各种资源对象的理解和定义 Kubernetes 中 Pod 的选举过程

  8. 1、CentOS部署Java开发环境

    一.安装jdk  jdk下载地址:http://www.Oracle.com/technetwork/java/javase/downloads/jdk-6u31-download-1501634.h ...

  9. ROS Industrial 简介

    ROS_I means ROS Industrial ROS_I 解决了哪些问题: 1. 让自动化可以互相协作,操纵器.末端执行器.感知系统/传感器,移动平台,周边设备,都可只用一种语言(ROS me ...

  10. 使用AutoMapper时Expression的转换

    此文章为转载:http://www.bubuko.com/infodetail-699735.html 参考链接: http://q.cnblogs.com/q/34480/   dudu有回复,其中 ...