Java内存区域

  对比与C和C++,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堆对象就必须考虑如何放置访问类型数据的相关信息,reference中存放的就是对象地址。



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

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

   

实际问题处理

堆溢出

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

栈溢出

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

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虚拟机---->java内存区域与内存溢出异常

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

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

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

  9. 2.1 自动内存管理机制--Java内存区域与内存溢出异常

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

随机推荐

  1. sqlliab7-8

    less-7 https://www.jianshu.com/p/20d1282e6e1d ?id=0')) union select 1,'2','<?php @eval($_POST[&qu ...

  2. 关于flex弹性布局

    http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

  3. 上传文件的input问题以及FormData特性

    1.input中除了type="file"还要加上name="file",否则$_FILES为空,input的name值就是为了区分每一个input的 2.va ...

  4. session开启慢的原因及解决办法

    做微信开发的时候发现微信回复特别慢,发个消息要好几秒才回复,发现不正常后就赶紧找答案,到最后发现是session_start()开启很慢,这是因为session缓存文件过多,默认缓存文件在:win:w ...

  5. The new SFCB broker fails to start with a SSL-related error: Failure setting ECDH curve name (secp22

    # openssl ecparam -list_curves secp384r1 : NIST/SECG curve over a 384 bit prime field secp521r1 : NI ...

  6. Spring Cloud 系列之 Stream 消息驱动(一)

    在实际开发过程中,服务与服务之间通信经常会使用到消息中间件,消息中间件解决了应用解耦.异步处理.流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构. 不同中间件内部实现方式是不一样的,这些中间 ...

  7. Java和php中的try-catch分析

    为什么80%的码农都做不了架构师?>>>   描述:对一个健壮的系统来讲,异常处理是必不可少的一部分,针对异常的管理,主要就是异常的捕获和处理操作,然而在php中使用try-catc ...

  8. 《WCF技术内幕》翻译3:第1部分_第1章_蓝月亮:普遍需求和普遍概念

    第一部分:WCF介绍    章节目录:    第1章:蓝月亮    第2章:面向服务    第3章:消息交换模式.拓扑和编排    第4章:WCF 101 第1章:蓝月亮    商业和市场对软件系统新 ...

  9. Nginx比SRS做得好的地方

    在nginx.org文档中,摘录了一篇nginx介绍的文章,Chapter “nginx” in “The Architecture of Open Source Applications”,这篇文章 ...

  10. search(9)- elastic4s logback-appender

    前面写了个cassandra-appender,一个基于cassandra的logback插件.正是cassandra的分布式数据库属性才合适作为akka-cluster-sharding分布式应用的 ...