1、jvm内存结构

静态编译:把java源文件编译成字节码文件class,这个时候class文件以静态方式存在。

类加载器:把java字节码文件加载到内存中

方法区:将字节码放到方法区作为元数据(简单名字+描述符)。

堆:对象(类的实例)

方法区和堆:运行时数据区在所有线程间共享

虚拟机栈、本地方法栈、程序计数器:运行时数据区线程私有

2、堆

(1)对于大多数应用来说,java堆是java虚拟机所管理的内存中的最大的一块

(2)java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,需要考虑线程安全的问题

(3)此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例对在这里分配内存

new Person();

(4)如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,OutOfMemoryError异常

 String [] str =new String[1000000];

如果再分配数组的内存之前将jvm的数值调小后便会发生此异常。

(5)是垃圾收集器管理的主要区域

堆内存溢出(OutOfMemoryError)问题:

堆既然有垃圾回收机制,为什么还会有内存溢出的问题呢?

因为垃圾回收器回收的是不被使用的对象,如果不停的产生对象而对象又都在被使用就会出现内存溢出

(6)JDK1.7开始,将StringTable从常量池移动到了堆中,String table又称为StringPool(字符串常量池)

永久带的内存回收效率较低,full GC才会触发,也就是老年代的空间不足才会触发。但是移动到堆中之后,只需要Minor GC即可触发垃圾回收,大大减轻了字符串对内存的占用

3、方法区

是各个线程共享的内存区域,虚拟机启动的时候创建

(1)存放的信息

已经被jvm加载的类的信息

常量

静态变量

及时编译器编译后的代码(JIT)

(2)JIT:热点代码编译后存储到方法区

  for(int i=0;i<100;i++){
add();
}

上面的代码编译后存放起来,避免反复编译

(3)编译的过程

(4)运行时常量池

常量池:是一个常量表

运行时常量池:

常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入到运行时常量池,并将里面的符号地址变为真实地址

4、程序计数器(PC Register)

(1)一块较小的内存空间,它的作用是当前线程所执行的字节码行号指示器(记录下一条jvm指令的执行地址)

(2)一个处理器只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器(线程私有)

(3)唯一一个在jvm中没有规定任何OutOfMemoryError的区域(java的规范所规定)

5、本地方法栈

为本地方法(不是由java代码编写的方法)的运行提供的内存空间

 protected native Object clone() throws CloneNotSupportedException;

该方法没有方法实现,底层是c或c++实现的

(1)栈是有深度的:

private Long aLong=1l;
public void test(int a,int b){
aLong++;
System.out.println(aLong);
test(a,b);
} public static void main(String[] args) {
Test1 test1=new Test1();
test1.test(0,0);
}

每调用一次占用一个栈帧:

栈的默认大小为5248,默认1M。

函数的调用过程:

6、虚拟机栈(每一个线程运行的时候所需要的内存)

每一个方法在执行的时候都会创建一个栈帧(一个栈帧对应一个方法的调用,栈帧即每一个方法需要的内存)用于存储分配基本类型和自定义对象的引用,用于存放,局部变量表、操作数栈、动态链接\方法的返回地址

每一个线程只有一个活动栈帧,对应着当前线程正在执行的那个方法

垃圾回收不涉及栈内存

可以通过指令来指定栈的大小,但是并不是栈的内存越大越好,栈的内存变大可能引起线程数量的减少程序反而会变慢

局部变量没有逃离方法的作用域是线程安全的(线程私有),当作为参数传递的变量或是局部变量作为返回值都不是线程安全的,因为可能被别的线程访问到

(1)一个栈中的多个栈帧

栈帧1先入栈,然后是栈帧2、栈帧3,相当于方法1调用方法2,方法2又调用了方法3,出栈的时候栈帧3先出栈,然后是栈帧2和栈帧3

(2)异常

StackOverflowError:

线程请求的深度大于虚拟机栈的深度(栈内存溢出),方法的递归调用容易出现

栈帧过大,直接将栈内存存满,发生的情况极其少

例如:定义一个学生类和一个班级类,一个学生只属于一个班级,在学生类里面有一个班级编号属性,一个班级有多个学生,班级类里面可以定义一个集合代表多个学生,在进行JSON转换的时候就会出现循环引用的现象,即一个学生对应一个班级,一个班级又有多个学生......,要把学生和班级的引用改为单向的,就不会出现循环引用的现象了。

OutOfMemoryError:扩展时无法申请到足够的内存

7、堆、栈、方法区

(1)字符串相关:

String string="q"+"w"+"3";

后面的三个字符只创建了一个对象,因为存在字符串的折叠

String string=new String("hello");

当常量池中已经有了“hello”字符串后在常量池中就不必再创建了,只需在栈内存中创建一个对象即可;但是,如果在常量池中没有“hello”字符串的话,就需要创建两个字符串对象了。

(2)JVM执行流程

public class Person {
private String name;
public void sayhello(String name){
System.out.println("hello"+name);
} public static void main(String[] args) {
Person person=new Person();
person.sayhello("Tom");
}
}

JVM去方法区寻找Person类信息如果我不到,Classloader加载Person类信息进入内存方法区
在堆内存中创建Person对象,并持有方法区中Person类的类型信息的引用
把person添加到执行main0方法的主线程java调用栈中,指向堆空间中的内存对象
执行person.sayHello0时,JVM根据person定位到堆空间的Person实例
根据Person实例在方法区持有的引用,定位到方法区Person类型信息,获得sayHello0字节码,执行此方法执行,打印出结果。

8、局部变量表

(1)存放了各种基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址)
(2)long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个

9、常量池

存放编译期生成的各种字面量和符号引用

jvm:内存结构(堆、方法区、程序计数器、本地方法栈、虚拟机栈)的更多相关文章

  1. 牛客网Java刷题知识点之内存的划分(寄存器、本地方法区、方法区、栈内存和堆内存)

    不多说,直接上干货!  其中        1)程序计数器:用于指示当前线程所执行的字节码执行到了第几行,可以理解为当前线程的行号指示器.每个计数器志勇赖记录一个线程的行号,所以它是线程私有的.    ...

  2. JVM活学活用——Jvm内存结构

    Java内存结构: JVM内存结构主要是有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间.From Survivor空间.To S ...

  3. Java中JVM内存结构

    Java中JVM内存结构 线程共享区 方法区: 又名静态成员区域,包含整个程序的 class.static 成员等,类本身的字节码是静态的:它会被所有的线程共享和是全区级别的: 属于共享内存区域,存储 ...

  4. JVM内存结构之堆、栈、方法区以及直接内存、堆和栈区别

    JVM内存结构之堆.栈.方法区以及直接内存.堆和栈区别 一.  理解JVM中堆与栈以及方法区 堆(heap):FIFO(队列优先,先进先出):二级缓存:*JVM中只有一个堆区被所有线程所共享:对象和数 ...

  5. JVM内存模型——堆(heap)、栈(stack)和方法区(method)

      JAVA的JVM的内存可分为3个区:堆(heap).栈(stack)和方法区(method) 堆区:堆内存用于存放由new创建的对象和数组.堆是JVM管理的内存中最大的一块,堆被所有线程共享,目的 ...

  6. JVM内存结构/JVM运行时数据区,以及堆内存的划分

    1.程序计数器: 程序计数器是线程私有的内存,JVM多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,当线程切换后需要恢复到正确的执 行位置(处理器)时,就是通过程序计数器来实现的.此内存区域 ...

  7. JVM内存的堆、栈和方法区

    JVM的内存分为堆.栈.方法区和程序计数器4个区域 存储内容:基本类型,对象引用,对象本身,class,常量,static变量 堆: 拥有者:所有线程 内容:对象本身,不存放基本类型和对象引用 垃圾回 ...

  8. jvm入门及理解(三)——运行时数据区(程序计数器+本地方法栈)

    一.内存与线程 内存: 内存是非常重要的系统资源,是硬盘和cpu的中间仓库及桥梁,承载着操作系统和应用程序的实时运行.JVM内存布局规定了JAVA在运行过程中内存申请.分配.管理的策略,保证了JVM的 ...

  9. JDK8的JVM内存结构,元空间替代永久代成为方法区及常量池的变化

    JVM的知识这里总结的很详细:https://github.com/doocs/jvm/blob/master/README.md,因此在本博客也不会再对其中的东西重复总结了. 现在很多文章关于JVM ...

  10. 转:JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )

    原文地址:JVM 内存初学 (堆(heap).栈(stack)和方法区(method) ) 博主推荐 深入浅出JVM 这本书 先了解具体的概念:JAVA的JVM的内存可分为3个区:堆(heap).栈( ...

随机推荐

  1. loadrunner通过web的post请求方法测接口

    loadrunner通过web的post请求方法测接口 loginapi() 模拟APP发送请求给Cloud, Action() "Name=input","Value= ...

  2. bzoj1603: [Usaco2008 Oct]打谷机 (纱布题)

    Description Input Output Sample Input Sample Output Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 7 ...

  3. 【问】:和=在map里面的区别

  4. bp(net core)+easyui+efcore实现仓储管理系统——入库管理之二(三十八)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  5. 先搞清楚这些问题,简历上再写你熟悉Java!

    原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...

  6. linux安装国产数据库(金仓数据库,达梦数据库,南大通用数据库)

    今天在公司做的任务是,在Linux的环境下安装三种数据库,结果一种数据库也没有安装好,首先遇到的问题是安装南大通用数据库遇到安装的第五步,就出现问题了,问题是Gbase SDK没有安装成功,以及Gba ...

  7. flask前端上传图片/文件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Ubuntu 系统下如何安装pip3工具

    一.[导读]Ubuntu 系统内置了 Python2 和 Python3 两个版本的开发环境,却没有内置相应的 pip3 管理工具,本文将介绍如何在Ubuntu下如何快速安装 pip3 工具,并升级到 ...

  9. 2020ubuntu1804server编译安装redis笔记(一)及报make test错误解决办法

    redis的大名我想大家都不陌生,今天在ubuntu server上进行编译安装,虽然apt也可以安装,但作为内存数据库,redis又是c开发的,编译安装,对机器的适应和性能更好. 安装笔记如下 第1 ...

  10. Oracle 11g rac中关于crsctl stop cluster/crs/has的区别

    转载至http://www.oracleplus.net/arch/1203.html,整理后得. 1 通过命令查看cluster/has/crs管理的内容 [root@11rac1 ~]# crsc ...