java内存结构
Java的内存结构
JVM的内存结构主要有三大块:堆、方法区和栈。堆内存是JVM中最大的一块,由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间、FromSurvivor空间和ToSurvivor空间,默认情况下年轻代是按照8:1:1的比例来分配。
方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为Java虚拟机栈和本地方法栈主要用于方法的执行。
JVM和系统调用之间的关系
方法区和堆是所有线程共享的内存区域;而java虚拟机栈、本地方法栈和程序员计数器是线程私有的内存区域。
1. Java堆(Heap)
对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块,Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,因此很多时候也被成为“GC堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代,再细致一点的有Eden空间、From Survivor空间、ToSurvivor空间等。
根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的空间内存中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OOM(OutOfMemoryError)异常。
2. 方法区(Method Area)
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它有一个别名Non-Heap(非堆),目的应该是与Java堆区分开。
对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。
Java虚拟机规范对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。
根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OOM(OutOfMemoryError)异常。
方法区(Method)用于存储类结构信息的地方,包括常量池、静态变量、构造函数等类型信息,类型信息是由类加载器在类加载时从类文件中提取出来的。
3. 程序计数器
程序计数器(Program Counter Register)是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址。Java多线程的实现,其实是通过线程间的轮流切换并分配处理器执行时间的方式来实现,在任何时刻,处理器都只会执行一个线程中的指令。在多线程的场景下,为了保证线程切换回来后,还能恢复到原先状态,找到原先执行的指令,所以每个线程都会设立一个程序计数器,并且各个线程之间不会互相影响,程序计数器为“线程私有”的内存区域。
如果当前线程正在执行Java方法,则程序计数器保存的是虚拟机字节码的内存地址,如果正在执行的是Native方法(非Java方法,JVM底层有许多非Java编写的函数实现),计数器则为空。程序计数器是唯一一个在Java规范中没有规定任何OutOfMemory场景的区域。
4. JVM栈(JVM Stacks)
虚拟机栈(Java Virtual Machine Stacks)和线程是紧密联系的,每创建一个线程时就会对应创建一个Java栈,所以Java栈也是“线程私有”的内存区域,这个栈中又会对应包含多个栈帧,每调用一个方法时就会往栈帧中创建并压入一个栈帧,栈帧是用来存储方法数据和部分过程结果的数据结构,每一个方法从调用到最终返回结果的过程,就对应一个栈帧从入栈到出栈的过程。
与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stacks Frame)用于存储局部变量表、操作栈、动态链接、方法出库等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,本局不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
虚拟机栈是一个后入先出的数据结构,线程运行过程中,只有一个栈帧是处于活跃状态的,被称为“当前活动帧栈”,当前活动帧栈始终是虚拟机栈的栈顶元素。
5. 本地方法栈
本地方法栈(Native Method Stack)和虚拟机栈的作用相似,不过虚拟机栈是为Java方法服务的,而本地方法栈是为Native方法服务的。
总结
- 所有线程共享的内存数据区:方法区、堆。而虚拟机栈、本地方法炸和程序计数器都是线程私有的。
- 存放于栈中的东西如下:
(1)每个线程中包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。对象都存放在堆区。
(2)每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
(3)方法的形式参数,方法调用完后从栈空间中回收。
(4)引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC。
- 存放于堆中的东西:
(1)存储的全部是对象,每个对象包含一个与之对应的class信息。
(2)JVM只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身。
- 存放于方法区的东西:
(1)存放线程所执行的字节码指令。
(2)跟堆一样,被所有线程共享,方法区包含所有的class和static变量;
(3)常量池位于方法区中
java内存结构的更多相关文章
- Java 内存结构备忘录
本文详细描述了 Java 堆内存模型,垃圾回收算法以及处理内存泄露的最佳方案,并辅之以图表,希望能对理解 Java 内存结构有所帮助.原文作者 Sumith Puri,本文系 OneAPM 工程师编译 ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- java内存结构学习的一种打开方式
用Java开发已经四年,中途学了python,Scala,接触这些开发语言后,总感觉Java就像老奶奶裹脚——又臭又长.然,Java虐我千百遍,我待Java如初恋.聊起Java,不得不谈Java的内存 ...
- Java内存结构详解
Java内存结构详解 Java把内存分成:栈内存,堆内存,方法区,本地方法区和寄存器等. 下面分别介绍栈内存,堆内存,方法区各自一些特性: 1.栈内存 (1)一些基本类型的变量和对象的引用变量都是在函 ...
- JVM之--Java内存结构(第一篇)
最近在和同事朋友聊天的时候,发现一个很让人思考的问题,很多人总觉得JVM将java和操作系统隔离开来,导致很多人不用熟悉操作系统,甚至不用了解JVM本身即可完全掌握Java这一门技术,其实个人的观点是 ...
- java内存结构JVM——java内存模型JMM——java对象模型JOM
JVM内存结构 Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存在,而有些区 ...
- 小菜鸟之java内存结构
JVM启动流程: JVM基本结构图: <深入理解Java虚拟机(第二版)>中的描述是下面这个样子的: Java中的内存分配: Java程序在运行时,需要在内存中的分配空间.为了提高运算效率 ...
- JVM高级特性-一、java内存结构区域介绍
区域划分: java虚拟机在执行程序的过程中,将内存分为功能不同的几个区域,如下图: 此图列出了内存划分的各个区域,其中 线程私有的:程序计数器.虚拟机栈.本地方法栈 线程共享的:堆.方法区 下面,逐 ...
- 深入理解java虚拟机【Java内存结构】
Java虚拟机规范规定的java虚拟机内存其实就是java虚拟机运行时数据区,其架构如下: 其中方法区和堆是由所有线程共享的数据区. Java虚拟机栈,本地方法栈和程序计数器是线程隔离的数据区. (1 ...
随机推荐
- APK改之理 手游修改改编安卓程序工具安装使用教程
APK改之理 手游修改改编安卓程序工具安装使用教程 --APK破解付费程序 apk改之理是pc平台上一款非常好用的apk反编译工具,他将反编译以及签名等功能集中在一起,并且拥有非常人性化的操作界面,如 ...
- Python:正则表达式(二):如何使用re.search()返回的匹配对象中的具体内容呢??
在上一篇中讲述了re.seach()会返回一个对象格式的数据,如下:<_sre.SRE_Match object; span=(16, 24), match='${phone}'> 那么问 ...
- 前后端分离--ajaxUpload异步上传文件成功,前端获取数据却失败的解决方案
转载:https://blog.csdn.net/baidu_32809053/article/details/78709951
- 分布式系列十二: Redis高级主题
持久化 Redis 支持持久化, 其持久化数据有两种方式. 两种可以同时使用. 如果同时使用, Reids 在重启时将使用 AOF 方式来还原数据. RDB 按照一定策略定时同步内存的数据到磁盘.文件 ...
- Theano.tensor.round函数学习,同时解决输出Elemwise{xxx,no_inplace}.0的问题
1. 出现Elemwise{xxx,no_inplace}.0 这是因为没有定义theano.function所致,参考下面错误示范: y = np.random.normal(size=(2,2 ...
- core ML学习
Core ML工具是一个Python包(coremltools),托管在Python包索引(PyPI)上. 从表格中可看出,支持caffe工具. 使用与模型的第三方工具相对应的Core ML转换器转换 ...
- selenium采用find_element_by方法识别页面元素
主要是练习获取页面中的各元素,马克 # coding:utf-8 import time from selenium import webdriver import unittest from pyt ...
- git知识总结-1.git基础之数据存储
1.前言 git包含四种对象文件: blob tree commit tag(目前没用到,暂时忽略) 2. git对象的关系 图 git三种对象关系 粗略一看,可以大致感觉出blob类似于文件 ...
- multiwan 脚本
以下为校区ACM实验室多拨脚本,使用了macvlan模块,具体策略路由和连接标记等思路就不解释了. #! /bin/bash getip() { |grep -o -e 'inet addr:[^ ] ...
- HTML基本语法
一.什么是HTML? HTML不是编程语言,是用来描述网页文档(页面结构)的一种标记语言: HTML指超文本标记语言(Hyper Text Markup Language),之所以称为超文本标记语言, ...