zoukankan      html  css  js  c++  java
  • JVM(2)—内存的划分

    我们知道快看小说网,在C++语言里,如果想使用一个对象,需要对其进行new操作;如果不用这个对象了,需要对其进行delete操作。一旦开发人员忘记写delete语句了,就会造成内存泄露。【内存被对象占用着不还,就叫内存泄露。】

    他的小仙女陈述安静java就聪明了,它从“手动”进化成了“自动”,把内存的控制权力交给了虚拟机。下面我们就来窥探一下jvm是怎么进行自动内存管理的。
    在这里插入图片描述

    自动内存管理分为两部分:给对象分配内存和回收分配给对象的内存。在本篇我们说说前者,也就是内存划分和内存分配。下篇再说GC(垃圾回收)。

    内存划分

    我们伪装学渣来看看虚拟机内存里都有什么东西。JVM的内存区域大致分为Class文件、类装载子系统、运行时数据区、执行引擎。今天我们只说说运行时数据区。【这张图是基于JDK7的。JDK7以前,常量池是存放在方法区的。从JDK7以后,常量池放到了堆中。】

    在这里插入图片描述

    • 线程公有

    在运行时数据区中,方法区和堆是属于线程公有的,也就是这两块区域是“循环利用”的,所以牧弯弯暴君要对其进行垃圾回收。其是在虚拟机启动时创建。

    • 线程私有

    虚拟机栈、本地方法栈、程序计数器是属于线程私有的,其与线程“同生死”,属于“一次性”的,所以花城和谢怜不用对其进行垃圾回收。

    (1)方法区
    存储锦瑟沈甫亭小说主角已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
    其中有一个运行时常量池。其存储的是Class文件中描述的符号引用,直接引用。在编译期和运行期都可以将新的常量放入此池子中。

    (2) 堆
    概念:
    如果说栈解决的是程序运行问题,即程序如何处理数据;则堆解决的是数据存储问题,即数据怎么放,放在哪。

    特点:
    a、堆是虚拟机内存中最大的一块,大概占内存的四分之三。比如一个32位windows平台中每个进程有2GB的内存,则一般将1.5GB的内存划分给堆。可见堆的所占空间之大。
    b、可处于物理上不连续的内存空间中,只要逻辑上是连续的即可。

    作用:
    魏婴莫玄羽存放对象实例,几乎所有的对象实例都在这里分配内存。

    分类:
    从内存回收的角度看,分为新生代和老年代。
    从内存分配的角度看,可划分出多个线程私有的分配缓冲区。

    (3)虚拟机栈

    虚拟机栈里面存储的是栈帧,栈帧里面存储的是局部变量表,操作数栈,动态链接,方法出口等信息。

    栈中的栈帧
    余欢祁北杨每个方法在执行的同时都会创建一个栈帧,一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

    栈帧中的局部变量表
    存放的是编译期可知的各种基本数据类型,对象引用,returnAddress类型。所以其所需的内存空间在编译期间就能完成分配,在运行期间不会改变其大小。
    在分配基本数据类型所占的空间时,除了64位的long和double类型的数据会占用2个局部变量空间,其余的数据类型只占用1个。

    (4)本地方法栈
    本地方法栈和虚拟机栈的作用是相同的,只不过虚拟机栈执行的是java方法,女配不掺和林淡本地方法栈执行的是Native方法。
    java方法就是开发人员写的java代码,Native方法就是一个java调用非java代码的接口。

    (5)程序计数器
    程序计数器中存放的是当前线程所执行的字节码的行号。jvm工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

    内存分配

    这部分我们说说对象在java堆中是如何分配,布局和访问的,以及内存分配的原则。

    对象的创建

    我们用new来创建对象,来看看系统运行到new时,虚拟机在干什么。此时的类就像一块肉,他要经过层层安检,才能到达人类的饭桌。

    第一步:查看在常量池中是否有对应的符号引用。【在方法区中进行】
    第二步:查看此类是否被加载,解析和初始化过。【在方法区中进行】
    第三步:领取新生对象的内存。有两种方式:指针碰撞和空闲列表。【在堆中进行】
    第四步:将分配到的内存空间初始化为零值。
    第五步:对对象进行必要的设置,比如其是哪个类的实例,对象的哈希码之类的。这些信息存放在对象的对象头之中
    第六步:如果java代码中对对象进行了赋初值,则会进行第六步:执行< init >方法。此方法的作用就是对对象进行初始化。
    ————————————————

    对象的内存布局
    对象在内存中的存储布局分为3部分:对象头+实例数据+对齐填充

    对象头
    对象头里面有两部分信息:
    (1)运行时数据,包括哈希码,GC分代年龄,锁状态标志等。
    (2)类型指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

    实例数据
    实例数据中存放的是代码中定义的各种类型的字段内容。

    对齐填充
    对齐填充起的是占位符的作用,不是必然存在的。其只要保证对象的大小是8字节的整数倍即可。

    对象的访问定位

    建立完对象后,郁淮徐以年我们就可以使用对象了。在使用时,怎么才能找到想找的对象?有两种方式:句柄和直接指针

    • 句柄

    句柄访问就是在java堆中划分出一块内存来作为句柄池,句柄中包含了对象实例数据和类型数据各自具体的地址信息。

    • 直接指针

    直接指针之所以“直接”,是因为它去除了句柄这个中介。所以在速度上比句柄快。
    在HotSpot虚拟机中,使用的是这种方式。


    说完了对象在java堆中是如何分配,布局和访问的,接下来我们说说内存分配的原则。

    内存分配的原则:

    堆大致分为新生代,老年代,永久代。暴君强宠:萌妃拽翻天对象的内存分配主要分配在新生代的Eden区,少数情况下会直接分配到老年代中。分配的规则不是100%固定的,取决于垃圾收集器组合和参数设置等。下面有几条分配原则可供参考。
    (1)对象优先在Eden分配。
    (2)大对象直接进入老年代。
    (3)长期存活的对象将进入老年代。
    (4)动态对象年龄判定。
    (5)空间分配担保。
    ————————————————

    学习累了,推荐一个看书的好网站www.kuaikanxs.cc

  • 相关阅读:
    Python 爬虫js加密破解(一) 爬取今日头条as cp 算法 解密
    Python 爬虫实例(2)—— 爬取今日头条
    Python 爬虫实例(1)—— 爬取百度图片
    python 操作redis之——HyperLogLog (八)
    python 操作redis之——有序集合(sorted set) (七)
    Python操作redis系列之 列表(list) (五)
    Python操作redis系列以 哈希(Hash)命令详解(四)
    Python操作redis字符串(String)详解 (三)
    How to Install MySQL on CentOS 7
    Linux SSH远程文件/目录 传输
  • 原文地址:https://www.cnblogs.com/Katerina/p/11372502.html
Copyright © 2011-2022 走看看