JVM内存管理之JAVA语言的内存管理概述
引言
内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑。不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓狂的内存溢出和泄露的问题。
可怕的事情还不只如此,有些使用其它语言开发的程序员,给JAVA程序员扣上了一个“不懂内存”的帽子,这着实有点让人难以接受。毕竟JAVA当中没有malloc和delete、没有析构函数、没有指针,刚开始接触JAVA的程序员们又怎么可能接触内存这一部分呢,更何况有不少JAVA程序员还是跳了专业半路出家的朋友。
不过事实尽管难以接受,但也确实有不少JAVA程序员对内存这部分可谓一窍不知,尽管掌握内存的相关知识,或许并不能给平时的开发带来翻天覆地的变化和好处,不过它仍然会潜移默化的提高你的技术水准,这一点在了解完内存管理之后,相信各位就会深有体会了。
内存划分
谈到内存这一词汇,它是在程序运行时才有的数据存储区域,而对于这一块区域的划分,各个虚拟机有各自的划分方式,不过它们都必须遵从JAVA虚拟机的基本规范去实现。
虚拟机规范中,将内存划分为六大部分,分别是PC寄存器、JAVA虚拟机栈、JAVA堆、方法区、运行时常量池以及本地方法栈。
JAVA虚拟机规范与JAVA虚拟机
这里还需要解释一下JAVA虚拟机规范和JAVA虚拟机的区别,顾名思义,JAVA虚拟机规范是一种对JAVA虚拟机实现的规范要求,是由oracle制定的,而我们平时常说的JAVA虚拟机一般是指的一种具体的JAVA虚拟机规范的实现。比如我们最经常使用的JAVA虚拟机hotspot,其实JAVA虚拟机还有很多种实现,甚至如果你对JAVA虚拟机规范有了深入的了解而且对此有兴趣的话,可以写一个自己的JAVA虚拟机,当然这其中的难度不难想象。
结构图
下图是引用于百度文库的一张JVM的结构图,由于运行时常量池是由方法区分配出来的区域,所以此图当中没有运行时常量池。
内存区域详解
针对上面这张图,内存就是指的矩形框当中运行期数据区这部分,下面简单介绍一下各个部分的作用:
1、PC寄存器(线程独有):全称是程序计数寄存器,它记载着每一个线程当前运行的JAVA方法的地址,如果是当前执行的是本地方法,则程序计数器会是一个空地址。它的作用就是用来支持多线程,线程的阻塞、恢复、挂起等一系列操作,直观的想象一下,要是没有记住每个线程当前运行的位置,又如何恢复呢。依据这一点,每一个线程都有一个PC寄存器,也就是说PC寄存器是线程独有的。
2、JAVA虚拟机栈(线程独有):JAVA虚拟机栈是在创建线程的同时创建的,用于存储栈帧,JAVA虚拟机栈也是线程独有的。
- 栈帧:简单点说,可以解释为是一个方法运行时,临时数据的存储区域,具体点说,它里面包括了数据和部分的过程结果,与此同时,它又肩负着处理方法返回值、动态链接以及异常分派的任务。栈帧是随着方法的创建而创建,随着方法的结束而销毁,如果方法抛出异常,也算方法结束。然而在每一个栈帧中,都有着自己的局部变量表以及操作数栈以及对当前类的运行时常量池的引用。
- 局部变量表:它是一个方法局部变量的列表,是在编译时期就写入了class文件当中。简单的理解,可以将它理解为一个对象数组,而里面按照索引0到length-1分别对应于每一个局部变量,特别的,如果是实例方法的局部变量表,第0个局部变量会是一个指向当前实例的引用,也就是this关键字,其余的局部变量则从索引1开始。
- 操作数栈:它是一个后进先出(LIFO)栈,而它的长度也是在编译时期就写入了class文件当中,是固定的。它的作用就是提供字节码指令操作变量计算的空间,比如简单的,对于int a=9这句话来说,就需要先将9压入操作数栈,再将9赋给a这个变量。
3、JAVA堆(全局共享):这一部分是JAVA内存中最重要的一部分,之所以说是最重要的一部分,并不是因为它的重要性,而是指作为开发人员最应该关注的一部分。它随着JAVA虚拟机的启动创建,储存着所有对象实例以及数组对象,而且内置了“自动内存管理系统”,也就是我们常说的垃圾搜集器(GC)。JAVA堆中的内存释放是不受开发人员控制的,完全由JAVA虚拟机一手操办。对于JAVA虚拟机如何实现垃圾搜集器,JAVA虚拟机规范没有明确的规定,也正因如此,我们平时使用的JAVA虚拟机中提供了许多种垃圾搜集器,它们采用不同的算法以及实现方式,已满足多方面的性能需求。
4、方法区(全局共享):方法区也是堆的一个组成部分,它主要存储的是运行时常量池、字段信息、方法信息、构造方法与普通函数的字节码内容以及一些特殊方法。它与JAVA堆的区别除了存储的信息与JAVA堆不一样之外,最大的区别就是这一部分JAVA虚拟机规范不强制要求实现自动内存管理系统(GC)。
5、本地方法栈(线程独有):本地方法栈是一个传统的栈,它用来支持native方法的执行。如果JAVA虚拟机是使用的其它语言实现指令集解释器的时候,也会用到本地方法栈。如果前面这两种都未发生,也就是说如果JAVA虚拟机不依赖于本地方法栈,而且JAVA虚拟机也不支持native方法,则不需要本地方法栈。而如果需要的话,则本地方法栈也是随每一个线程的启动而创建的。
上面五个内存区域,除了PC寄存器之外,其余四个一般情况下,都要求JAVA虚拟机实现提供给客户调节大小的参数,也就是我们常用的Xms、Xmx等等。
内存管理
内存管理分为内存分配和内存释放,看一下上面的五个内存区域,其实可以大致分为两部分,一部分是全局共享,一部分是线程独有。
对于线程独有的这部分内存,都是随着线程的启动而创建,而当线程被销毁时,内存也就随之释放。这一部分内存,不需要垃圾搜集器的管理,而是JAVA虚拟机来主动管理,每当一个线程被创建的时候,JAVA虚拟机就会为其分配相应的PC寄存器和JAVA虚拟机栈,如果需要的话,还会有本地方法栈。相应的,当一个线程被销毁的时候,JAVA虚拟机也会将这个线程所占有的内存全部释放。
相对于线程独有的那部分内存,全局共享的这部分内存更加难以处理,不过这只是针对于虚拟机的实现来说,因为这一部分内存是要实现自动内存管理系统(GC)的。
全局共享的这部分内存(以下简称堆),内存分配主要是由程序员显示的使用new关键字来触发的,至于new出来的这部分内存在哪分配,如何分配,则是JAVA虚拟机来决定。而这部分内存的释放,则是由自动内存管理系统(以下简称GC)来管理的。
通常情况下,堆内存分配是要依赖于GC的策略与实现的,在分配的时候,就要考虑好到时候如何回收这部分内存。也是正因为如此,对于内存分配这一部分的讲解来说,我们必须得先了解内存是如何被回收的,才能更好的理解内存要怎么被分配。
结束语
本次对于JAVA语言中内存管理的概述就到此结束了,接下来的章节会着重讲解一下GC的原理以及实现方式,请各位敬请期待吧。
http://www.cnblogs.com/zuoxiaolong
JVM内存管理之JAVA语言的内存管理概述的更多相关文章
- JVM内存管理------JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- 1 - JVM随笔分类(java虚拟机的内存区域分配(一个不断记录和推翻以及再记录的一个过程))
java虚拟机的内存区域分配 在JVM运行时,类加载器ClassLoader在加载到类的字节码后,交由jvm的执行引擎处理, 执行过程中需要空间来存储数据(类似于Cpu及主存),此时的这段空间的分 ...
- java语言中的多态概述
多态:一个对象相应着不同类型 多态在代码中的体现:父类或接口的引用指向其子类对象. 多态的优点: 提高了代码的扩展性,前期定义的代码能够使用后期的内容. 多态的弊端: 前期定义的内容不能使用后期子类中 ...
- Java语言基础(方法重载概述和基本使用)
方法重载概述: 在同一个类中,允许存在一个以上的同名方法,只要他们的参数列表不同(即参数类型或者参数个数)即可. 方法重载特点: 1. 与返回值类型无关,只看方法名和参数列表 2. 在调用的时候,虚拟 ...
- 【Java】JMM内存模型和JVM内存结构
JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...
- 深入理解JAVA虚拟机 自动内存管理机制
运行时数据区域 其中右侧三个一起的部分是每个线程一份,左侧两个是所有线程共享的. 程序计数器(Program Counter Register) 英文名称叫Program Counter Regist ...
- java中栈内存与堆内存(JVM内存模型)
java中栈内存与堆内存(JVM内存模型) Java中堆内存和栈内存详解1 和 Java中堆内存和栈内存详解2 都粗略讲解了栈内存和堆内存的区别,以及代码中哪些变量存储在堆中.哪些存储在栈中.内存中的 ...
- 高性能JAVA开发之内存管理
这几天在找一个程序的bug,主要是java虚拟机内存溢出的问题,调研了一些java内存管理的资料,现整理如下: 一.JVM中的对象生命周期 对象的生命周期一般分为7个阶段:创建阶段,应用阶段,不可视阶 ...
- java优化占用内存的方法(一)
java做的系统给人的印象是什么?占 内存!说道这句话就会有N多人站出来为java辩护,并举出一堆的性能测试报告来证明这一点.其实从理论上来讲java做的系统并不比其他语言开发出来的 系统更占用内存, ...
随机推荐
- 【2018多校第一场】hdu6308-Time Zone(日期)
Problem Description Chiaki often participates in international competitive programming contests. The ...
- LeetCode OJ:Gray Code(格林码)
The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...
- C++设计模式之-建造者模式
建造者模式的定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示(DP).<大话设计模式>举了一个很好的例子——建造小人,一共需建造6个部分,头部.身体.左右手.左 ...
- diff和patch 打补丁
在Linux环境下,有两个工具用来给project打补丁,即diff和patch diff diff具有比较功能.可以使用man命令查看其使用方法. NAME diff ...
- c# IE 清除缓存
Response.Buffer = true; Response.ExpiresAbsolute = System.DateTime.Now.AddSeconds(-); Response.Expir ...
- d3.js(v5.7)的比例尺以及坐标轴
直接上代码了,这里的一些函数用的是之前我自己封装的函数(包括attr的obj支持和节点数量和数据数量的自动匹配),若有不明白的,可以查看之前的博客: 页面的效果如下: 接下来继续添加坐标轴: 最终:
- 利用层序遍历(含空节点)和中序遍历重建二叉树 python
给定一颗二叉树的层序遍历(不含None的形式)和中序遍历序列,利用两个序列完成对二叉树的重建. 还是通过一个例子来说明整个过程,下图所示的二叉树,层序遍历结果为[a,b,c,d,e],中序遍历结果为[ ...
- UICollectionView 数据库元素分组 多种section分开显示
第一遍 复杂方法 : 数据库查询一个表中userID 然后进行分类 中间去重 获得ID个数 放到section 中 显示 #pragma mark - 查询不同的ID 各数 - (void)c ...
- NSArray中的对象进行排序
看在iOS中有哪些方法可以对NSArray中的对象进行排序.下面是目录: 小引 使用NSComparator进行排序 使用NSDescriptor进行排序 使用selector进行排序 小引 我们将要 ...
- librec库
固定初始化矩阵值 net.librec.math.structure -> class DenseMatrix -> void init()