第8章:JVM内存管理

Java和C++之间由一堵内存动态分配和垃圾收集器的“高墙”,墙外人想进去,墙内人想出去。因为在Java中,分配内存和回收内存都是由JVM自动完成的,很少遇到C++程序中内存泄漏问题。但是这些特点有一点点惯坏了Java程序员,当遇到OutofMemoryError,该怎么解决?所以我们需要了解Java是如何管理内存的,并能根据错误日志快速定位出错原因。

物理内存与虚拟内存

  • 物理内存
  1. 物理内存就是RAM(随机存储器),以及寄存器(存储计算单元指令的中间结果,寄存器的大小决定了一次计算可使用的最大数值)。
  2. 连接处理器与RAM或者处理器与寄存器的是地址总线,地址总线的宽带影响物理地址的索引范围,决定了处理器一次可从寄存器或内存中获取多少比特。同时也决定了处理器最大可寻址的地址空间。
  3. 运行程序需现象操作系统申请内存地址,操作系统管理内存的申请空间是按进程来管理的,每个进程拥有一段独立的地址空间,不能相互重合,操作系统保证每个进程只能访问自己内存空间。
  • 虚拟内存
  1. 虚拟内存可使多个进程在同时运行时共享物理内存,只是空间上的,逻辑上不能访问。
  2. 虚拟内存可以提高内存利用率,操作系统把不在活动的进程的物理内存的数据移到磁盘文件中,将高效的物理内存留给正在活动的程序使用。

内核空间和用户空间

计算机的姿势空间分为内核空间和用户空间:

  • 程序能够使用的是用户空间的内存
  • 内核空间是操作系统运行时使用的用于程序调度、虚拟内存的使用或者连接硬件资源等的程序逻辑。

Java的使用内存的组件

Java堆

  1. Java堆是Java虚拟机管理的内存最大的一块,用于存放对象实例,几乎所有的对象实例分配内存都是在堆上完成。
  2. Java堆是垃圾收集器管理的主要区域,因此又被称为“GC堆”
  3. Java堆中内存管理由JVM来控制;对象创建由Java应用程序控制;对象所占的内存释放由垃圾收集器完成。

线程

  1. JVM运行实际程序的实体就是线程,每一个线程创建,JVM就会为它创建一个堆栈
  2. 线程所占空间相比堆空间来说比较小,但是过多,线程堆栈使用的总内存也会很大

类和类加载器

  1. 类加载器是按需加载,比如加载一个jar包,不是加载jar包中所有的类,只会加载程序中明确使用的类到内存中。
  2. 可能会出现重复加载,导致永久代内存泄漏

NIO(重点,需要参考其他资料来系统学习)

  1. 在JDK1.4版本添加了新I/O(NIO)类库,引入一种基于通道和缓冲区来执行I/O的新方式;

JNI

JNI技术可使本机代码(如C语言程序)可以调用Java方法,就是通常所说的native memory;

JVM内存结构

JVM按照运行时数据的存储结构来划分没存结构的:

PC寄存器

严格来说是一个数据结构,用于保存当前正常执行的程序的内存地址。(记录中断线程的程序的内存地址)

Java栈

  1. 每创建一个线程时,JVM会为线程创建一个对应的Java栈,Java栈中又包含多个栈帧(一个方法就是一个栈帧),每个栈帧含有一些内部变量(方法内的变量)、操作栈和方法返回值。
  2. Java栈与Java线程对应的,这个数据不是共享的,所以不用担心数据一致性问题,也不存在同步锁的问题

  1. 堆是Java对象的地方,是JVM管理Java对象的核心存储区域,是Java程序员最关心的。
  2. 堆是被所有Java线程所共享的,需要注意同步问题,方法和对应的属性需要保持一致性。

方法区

JVM方法区是用于存储类结构信息的地方,也属于Java堆的一部分,也就是通常说的Java堆的永久代,这个区域的被所有的线程共享。

运行时常量池

Runtime Constant Pool代表运行时每个class文件中的常量表

本地方法栈

本地方法栈是为JVM运行Native方法准备的空间

JVM内存分配策略

  1. 静态内存分配:
    • 在程序编译时就能确定每个数据在运行时的存储空间需求,因此在编译时就给他们分配固定的内存空间。
    • 此方法不允许程序代码有可变数据结构,也不允许有嵌套或者递归的结构出现。
  2. 栈内存分配(动态存储分配)
    • 根据程序模块所需的数据区大小才能够为其分配内存
    • 栈内存分配方式按照先进先出的原则进行分配
  3. 堆内存分配
    • 当程序真正运行带相应代码时才会知道空间大小

Java中内存分配详解

  1. Java堆的分配和线程绑定一起,新建线程,JVM为线程创建一个新的Java栈,线程方法的调用和返回对应这个Java栈的压栈和出栈。栈中存放基本类型的变量数据(int ,shortmlong,byte,double,boolean,char)和对象句柄(引用)。
  2. 每个应用程序都唯一对应一个JVM实例,每个实例对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,有应用程序共享。
  3. 从堆和栈的功能和作用来说:堆主要是来存放对象,栈主要用来执行程序。

JVM回收策略

静态内存分配和回收

这些内存不会在程序执行时发生变化,知道程序执行结束时内存才被回收。例如Java的类和方法中的局部变量包括原生数据类型(int ,long,char)和对象的引用都是静态分配内存。

动态内存分配和回收

内存的分配是在对象创建时发生的,内存的回收也是以对象不再引用为前提的。

如何检测垃圾

垃圾收集器完成的两件事:

  • 能够正确的检测出垃圾对象
  • 能够释放垃圾对象占用的内存空间
    只要对象不再被其他活动对象引用,这个对象可以被回收;

基于分代的垃圾收集算法(Hotspot中使用)

设计思路:将对象按照寿命长短来分组,分为年轻代和老年代,新创建的对象被分为年轻代,如果对象经过几次回收后任然存活,那么再把这个对象划分为年老代。年老代的收集额度不像年轻代那么频繁,这样减少了每次垃圾收集时所要扫描的对象的数量,从而提高了垃圾回收效率。
将堆划分为若干个子堆,每个子堆对应一个年龄代:
在这里插入图片描述

Hotspot的三类垃圾收集算法:

  1. Serial Collector
  2. Paralle Collector
  3. CMS Collector
    在这里插入图片描述

内存问题分析

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值