一、java运行时数据区

  也可以称为java内存区域,和java内存模型不是一回事,不要弄混,这里基于jdk1.8之前

1.1、方法区

  线程共享,类装载过程中产生的java.lang.Class对象保存在方法区,而不是堆,请参考《深入理解java虚拟机》P215

  jdk1.8之前HotSpot通过永久带实现方法区,为了把GC可以像堆一样管理内存,能够复用代码,1.8移除永久带,通过本地内存实现方法区,

其他虚拟机没有永久带的概念,因为更容易出现内存溢出

  主要存放类信息、常量、静态变量、即时编译后的代码等

  垃圾回收主要是针对常量池回收和类型的卸载,这块区域的回收很难,尤其是类型卸载,可以选择不进行垃圾回收,但是回收很有必要的

  PS:jdk1.8及以后,方法区被移除,通过元空间实现,而元空间使用的是直接内存,可以使用参数:-XX:MetaspaceSize来指定元数据区的大小

1.2、虚拟机栈

  线程私有,生命周期和线程相同,每执行一个方法都会创建一个栈帧,从执行到结束,对应着栈帧在虚拟机栈的入栈到出栈过程,可以类比

数据结构中的栈,java方法两种返回方式:

  1、return语句

  2、抛出异常

  这两种方式都会导致栈帧被弹出

  栈帧:

    保存着局部变量表、操作数栈、方法出入口等

  局部变量表:

    用来保存方法参数和返回值,也就是基本数据类型、对象的引用、returnAddress类型(指向一个字节码指令的地址)

  double和long占用两个局部变量空间(variable slot),其余占用1个,slot空间大小在编译期间就确定,方法运行期间无法改变

  PS:可能出现Stack OverflowError、OutOfMemoryError错误

1.3、本地方法栈

  线程私有,和虚拟机栈相似,一个为Java方法服务,一个为了本地方法服务,本地方法栈中方法实现的语言、方式等没有规定,由具体的虚拟机

确定,在HotSpot中只有栈,没有虚拟机栈和本地方法栈的区别。

  本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

  PS:可能出现Stack OverflowError、OutOfMemoryError错误

1.4、堆

  线程共享,这是虚拟机内存最大的一块区域,也是GC的主要区域,几乎所有的对象和数组都保存在这里

  内存回收的角度分为:

    新生代:Eden Space、From Survivor、To Survivor

    老年代:

      1、主要用来保存大对象(可以通过-XX:PretenureSizeThreshold 设置大对象的阀值)

      2、或者从新生代经过15次 minor GC存活下来的对象(-XX:MaxTenuringThreshold)        

      3、第二条不是绝对的,VM动态判断,如果Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该

年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold要求的年龄

  默认Eden Space:From Survivor:To Survivor=8:1:1,可以通过-XX:SurvivorRatio调节,一般不需要新生代和老年代默认是1:2,

  可以通过-XX:NewRatio调节

  PS:进一步划分的目的是更好地回收内存,或者更快地分配内存。

1.5、程序计数器

  线程私有,是一块很小的内存区域,记录着当前虚拟机字节码指令的地址(对于JNI,值为undefined),字节码解释器通过改变计数器的值来

选择下一条执行的字节码,分支、循环、跳转、异常处理、线程恢复等功能都要依靠计数器。

  线程上下文切换的时候,为了能够恢复到正确的执行位置,需要每个线程都拥有一个独立的线程计数器,互不影响。

  PS:唯一一个没有规定OOM的区域

1.6、直接内存

  不属于Java内存区域,有可能出现OOM,jdk1.4出现了NIO,它可以通过Native函数库分配堆外内存,通过Java堆中的DirectByteBuffer对象

作为引用进行操作,在某些场景明显提高性能,以为避免了Java堆和Native堆来回复制数据。

  直接内存的分配不受Java堆大小限制,而是收到本机总内存的限制。

1.7、本地内存

  就是JMM的概念了,后面写JMM的时候再讲

二、常量池

2.1、字符串常量池

  在HotSpot中通过StringTable类实现功能,StringTable是一个hash表,默认长度大小1009,被所有类共享。字符串常量由字符组成,保存在

StringTable上面。在jdk1.6当中,StringTable的长度是固定1009,如果存放在StringTable中的字符串很多,造成hash冲突的几率很大,链表过

长,当通过String.intern()查找String Pool时,性能就会降低。

  在jdk1.7当中,StringTable的长度可以通过-XX:StringTableSize设置

存放的内容:

  String.intern()主要是为了复用字符串常量,节省内存空间

  在jdk1.6及以前的版本,存放的都是字符串常量,使用""声明的字符串都存储在这,例如:String str = "abc";

  在jdk1.7之后,String.intern()发生变化,返回对象的引用,因此除了字符串常量,也可以存放堆中字符串常量的引用

  PS:在jdk1.7之后,字符串常量池从方法区转移到堆中

2.2、class常量池

  首先java代码通过javac编译成class文件,class文件中保存着类的相关信息(版本,类、字段、方法、接口等信息),除此之外,还有Class

常量池,用来存放编译器产生的各种字面量(Literal)和符号引用(Symbolic References),每个class文件都有一个class常量池。

  字面量:1.String  2.基本数据类型  3.声明final的常量

  符号引用:1.类和方法的全限定名(类似于com.cfets.**.**这种)  2.字段的名称和描述符  3.方法的名称和描述符

2.3、运行时常量池

  就是class常量池被加载到方法区之后的版本,区别就是:字面量可以通过String.intern()动态添加,符号引用解析为直接引用(类加载的

解析阶段)

  当类加载到内存之中,jvm会把class常量池的内存存放到运行时常量池,所以,运行时常量池也是每个class都有的。

  符号引用:上述有说明。以一组符号来描述所引用的目标,只要能定位到目标,无论是任何形式的字面量,和jvm实现的内存布局无关。

  直接引用:直接指向目标的指针、相对偏移量或者间接定位到目标的句柄,句柄和指针对应对象的访问定位方式,和jvm实现的内存布局有关。

  PS:JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池

java虚拟(一)--java内存区域和常量池概念的更多相关文章

  1. Java中常用的内存区域

    在Java中主要存在4块内存空间,这些内存空间的名称及作用如下. 1.  栈内存空间: 保存所有对象名称(更准确的说是保存了引用的堆内存空间的地址). 2.  堆内存空间: 保存每个对象的具体属性内容 ...

  2. java中的堆、栈、常量池

    java中的堆.栈.常量池 分类: java2010-01-15 03:03 4248人阅读 评论(5) 收藏 举报 javastring编译器jvm存储equals Java内存分配: 1. 寄存器 ...

  3. 详细介绍Java中的堆、栈和常量池

    下面主要介绍JAVA中的堆.栈和常量池: 1.寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈 存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...

  4. JVM学习笔记(一):Java虚拟机和虚拟机内存区域

    为什么Java程序需要运行在虚拟机上 因为Java在设计之初的跨平台特性,我们知道Java程序是运行在Java虚拟机上的.如果你要问为什么Java程序要运行在虚拟机上,我可以反问你几个问题. 为什么买 ...

  5. Java虚拟机运行时内存区域简析

    figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...

  6. 【java】JVM的内存区域划分

    学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行 ...

  7. java运行时的内存区域

    1.概述 java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线 ...

  8. java中的常用内存区域总结

    <开发实战经典>     (1)栈内存空间:保存所有的对象名称     (2)堆内存空间:保存每个对象的具体属性内容     (3)全局数据区:保存static类型的属性     (4)全 ...

  9. Java内存中的常量池

    1,java内存模型简介 <深入理解java虚拟机>里将java内存分为如下五个模块: 堆-堆是所有线程共享的,主要用来存储对象. 其中,堆可分为:新生代和老年代两块区域.使用NewRat ...

随机推荐

  1. Linux 编译C++ 与 设置 Vim

    1. Linux 下编译c++ vim test.cpp    // 创建文件 g++ test.cpp    // 编译文件 ./a.out         // 执行文件 g++ test.cpp ...

  2. YTU 2633: P3 数钱是件愉快的事

    2633: P3 数钱是件愉快的事 时间限制: 1 Sec  内存限制: 128 MB 提交: 387  解决: 215 题目描述 超市收银员的钱盒里,各种钞票总是按照面额分类整理,这样做可以提高效率 ...

  3. 解决vs2010无法找到System.Data.OracleClient的引用问题

    解决vs2010无法找到System.Data.OracleClient的引用问题 2012-2-19 09:12| 发布者: benben| 查看: 7627| 评论: 0   摘要: 在vs201 ...

  4. c# IP从192.168.1.1转成int类型

    找了一些资料,总结如下: 方法1 .net提供的方法转换IP地址 //字符串转换为数字 System.Net.IPAddress ipaddress = System.Net.IPAddress.Pa ...

  5. 自定义Notification实现例子

    1.自定义view: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...

  6. IJ:工程配置Tomcat

    ylbtech-IJ:工程配置Tomcat 1.返回顶部 1. 1.2. 1.3. 1.4. 2. 2.返回顶部 1. 2. 3.返回顶部 1. 2. 4.返回顶部 0.修改文件位置 D:\work- ...

  7. Linux系统基本信息查看

    Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等等,整个CPU信息一目了然. 1.# uname -a   (Linux查看版本当前操作系统内核信息)   2.# ...

  8. bzoj 1633: [Usaco2007 Feb]The Cow Lexicon 牛的词典【dp】

    预处理出g[i][j]表示原串第i个匹配第j个单词需要去掉几个字母(匹配不上为-1) 设f[i]为i及之后满足条件要去掉的最少字母 倒着dp! f[i]初始为f[i+1]+1,转移方程为f[i]=mi ...

  9. 使用nginx和tomcat配置反向代理和动静分离

    背景 本人主修的编程语言是Java语言,因此最开始接触的Web开发也是JSP技术.使用Java开发的Web应用需要部署在专门的服务器程序上运行,比如Tomcat.但是一般很少会有人将Tomcat作为用 ...

  10. Linux系统编程---文件I/O(open、read、write、lseek、close)

    文件描述符 定义:对内核而言,文件描述符相当于一个文件的标识,它是一个非负整数,当打开(open)一个现有文件或者创建(creat)一个新文件时,内核会向进程返回一个文件描述符 在unix中(文件描述 ...