Java内存管理和垃圾回收

性能指标

java.lang.Runtime.getRuntime()
得到程序使用/空闲的内存

Runtime runtime = Runtime.getRuntime();

// Run the garbage collector
runtime.gc();

// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();

long time = System.currentTimeMillis();
//get current time

动态内存分配: new()
动态内存回收:delete()

内存管理三种基本模式

  • 静态内存分配 Static allocation
    在编译阶段就已经确定好了内存分配
  • 动态内存分配 Dynamic allocation
    在运行时动态分配内存,建立新的内存对象
    基于堆和栈的内存管理都是动态分配 (heap-based / stack-based)

以下三种模式的区别在于:如何与何时在程序对象(reference)与内存对象(object)之间建立联系

Static 静态

在将程序load进内存的时候、或开始执行时,确定所有对象的分配
运行时无法改变
缺点:不支持递归,不支持动态创建的可变长的复杂数据类型

Stack-based mode 动态,基于栈

缺点:无法支持复杂数据类型
原因:某些对象延续的时间比创建它的方法所延续的时间更长(所以stack不行)

Heap-based mode(free mode) 动态,基于堆

在一块内存里分为多个小块,每块包含一个对象,或者未被占用
代码中的一个变量ref可在不同时间被指向到不同的内存对象上,无法在编译阶段确定。内存对象也可以进一步指向其他对象
堆:自由模式的内存管理,动态分配,可管理复杂的动态数据结构

Java内存管理模型

如何在堆heap上创建新对象
当某个对象不再有reference指向它,如何删除对象、释放内存

每个在JVM运行的线程都有自己的线程栈.thread stack,管理其局部数据,各栈之间彼此不可见

  • The thread stack contains information about what methods the thread has called to reach the current point of execution.
    所有局部的基本数据类型都在栈上创建(All local variables of primitive types)

One thread may pass a copy of a primitive variable to another thread, but it cannot share the primitive local variable itself.
多线程之间传递基本类型数据,传递的是copy,而非基本类型局部变量本身(与函数传参类似)

所有对象都在堆上创建

  • This includes the object versions of the primitive types (e.g. Byte, Integer, Long, etc).
  • 即使对象object是局部变量local,也是在堆上创建
    在这里插入图片描述
    堆上创建的对象可被所有线程共享引用
    一个线程可访问对象时,就可以访问对象内的成员变量
    如果两个线程调用同一个对象上的某个方法,它们都可以访问这个对象的成员变量,但每个线程分别保留对局部变量的拷贝。

Java Virtual Machine (JVM)内存结构

在这里插入图片描述在这里插入图片描述

  • Pass arguments to methods
  • Return a result from a method
  • Store intermediate results while evaluating expressions
  • Store local variables

  • Objects
  • Arrays
  • By using “new” operator

Method Area/Metaspace

  • 用于存储被VM加载的类信息、常量、静态变量等,e.g.类名,类方法名
  • HotSpot JVM中用Permanent Area (Perm)实现该区域,并作为heap的一部分
  • Java 8之后改名为Metaspace (使用native memory)

Native Stacks 本地方法栈

  • manage native methods (coded in C) used by JVM

Program Counter Register (PC)

  • 代码行号指示器,用于指示,跳转下一条需要执行的命令

e.g.

  • 局部变量是一个对象的引用,那么这个引用存在线程栈中,指向的对象存在堆中
  • 一个对象的基本数据类型的成员存在中,如果一个成员变量是对一个对象的引用,也存在堆中。即一个对象的不是static的任何成员变量都存在堆中。static的成员变量存储在method area中
  • 静态类变量存储在 Heap/Method Area
    在这里插入图片描述

垃圾回收

可达和不可达对象

Reachable Objects vs. Unreachable Objects
内存回收的首要问题:如何把可达对象与不可达对象分离开来?

roots of a computation 根对象

  • The system’s root object
  • Any object attached to a local entity or formal argument of a routine currently being executed (including the local entity result for a function)
  • In common language implementations roots include
    • Words in the static area 静态区域的数据
    • Registers 寄存器
    • Words on the execution stack that point into the heap. 目前的执行栈中的数据所指向的内存对象
      在这里插入图片描述
      活对象:从root可达的对象
      死对象:从root不可达,将被内存回收

GC的成本指标

  • Execution time 执行时间
  • Memory usage 所占用的内存/对程序所使用内存的影响
  • Delay time 延迟时间

四种算法

Reference counting 引用计数

Keep a note on each object in your garage, indicating the number of live references to the object. If an object’s reference count goes to zero, throw the object out (it’s dead).

Mark-Sweep 标记-清除

Put a note on objects you need (roots).
Then recursively put a note on anything needed by a live object.
Afterwards, check all objects and throw out objects without notes

Mark-Compact 标记-整理

Put notes on objects you need.
Move anything with a note on it to the back of the garage.
Burn everything at the front of the garage (it’s all dead).

Copying 复制

Move objects you need to a new garage.
Then recursively move anything needed by an object in the new garage.
Afterwards, burn down the old garage (any objects in it are dead)!

JVM垃圾回收及其调优

在JVM中,在四种GC方法基础上做进一步的包装,以提高GC性能
Java GC将堆分为不同的区域,各区域采用不同的GC策略,以提高GC的效率
To see that the garbage collector starts working add the command line argument “-verbose:gc” to your virtual machine.

JVM内存分区

内存分区:
将堆内存分成三部分:新生代 young generation,旧生代old generation,永久区permanent generation(Java8后改名为metaspace)

  • 刚创建的对象被放在YG(Eden S0 S1)
  • 存活一段时间后被升入OG
  • PG里存放VM和Java class metadata和Strings和类静态变量在这里插入图片描述

Java GC策略

GC策略:
只有当某个区域不能再为对象分配内存时(满),才启动GC
年轻代:

  • 只有一小部分对象可较长时间存活,故采用copy算法减少GC代价
  • minor GC
    • 初始:eden区满且S-from区为空时,一次minor GC执行,eden区存活的对象移入S-to区,
    • eden区满时,一次minor GC执行,eden区和S-from中存活的对象移入S-to区,eden和S-from区清空,存活对象只存在与S-from区
    • 三个区域之间的copy
    • 如果多次minor GC后对象仍存活,则将其copy到old generation
  • 所需时间较短

年老代:

  • 这里的对象有很高的幸存度,使用Mark-Sweep或Mark-Compact算法
  • 如果old generation满了意味着无法进行下一次minor GC了,则启动full GC
  • Minor GC和full GC独立进行,减小代价
    永生代:
    当perm generation满了之后,无法存储更多的元数据,也启动full GC

GC调优

尽可能减少GC时间,一般不超过程序执行时间的5%
一旦初始分配给程序的内存满了,就抛出内存溢出异常

"Exception in thread java.lang.OutOfMemoryError:Java heap space".
  • Specifying VM heap size 确定堆的大小
  • Choosing a garbage collection scheme 选择GC模式
  • Using verbose garbage collection to determine heap size 使用verbose GC参数查看内存详细信息以确定堆的大小
  • Automatically logging low memory conditions 自动记录内存将要不足的情况
  • Manually requesting garbage collection 手工请求GC
  • Requesting thread stacks
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值