软件构造 第八章第一二节

第八章第一节 软件构造性能的度量原理

1. 内存管理模式

静态

-定义:静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源。

-程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用完毕时,系统会自动释放所占用的内存空间;

-不支持递归,不支持动态创建可变长的复杂数据类型;

-在程序执行期内实体至多关联一个运行时对象

eg: 基本类型,数组

 

动态-基于栈

-栈定义:方法调用和局部变量的存储位置,保存基本类型

-如果一个方法被调用,它的栈帧被放到调用栈的顶部

-栈帧保存方法的状态,包括执行哪行代码以及所有局部变量的值

-栈顶始终是当前运行方法

-一个实体可以在运行时连续地连接到多个对象,并且运行时机制以堆栈中的后进先出顺序分配和释放这些对象

-栈无法支持复杂数据结构

动态-基于栈

-堆定义:在一块内存里分为多个小块,每块包含 一个对象,或者未被占用

-自由模式的内存管理,动态分配,可管理复杂的动态数据结构

-代码中的一个变量可以在不同时间被关联到不同的内存对象上,无法在编译阶段确定。内存对象也可以进一步指向其他对象

 

 

2. Java Memory Model

  • 线程栈:每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间)
    • 每个线程有自己的栈,管理其局部数据,各栈之间彼此不可见
    • 所有局部的基本数据类型都在栈上创建
    • 多线程之间传递数据,是通过复制而非引用
  •  堆:所有对象(即使是局部变量的object)都是在堆上创建的
    • 主内存可被多线程共享

 

  • 一个基本类型的局部变量,一直被保存在线程栈中
  • 一个对象类型的局部变量,其引用保存在线程栈 中,对象本身存在堆中
  • 对象可能包含方法,这些方法可能包含局部变量。这些局部变量存储在线程栈上,并且该方法所属的对象存储在堆
  • 对象的原始成员变量存储在堆上。如果一个成员变量是一个对象的引用,它将被存储在堆
  • 静态类变量保存在堆上

 

 

Garbage Collection

在静态内存分配模式下,无需进行内存回收:所有都是已确定的

在栈上进行内存空间回收:按block(某个方法)整体进行

在heap 上进行内存空间回收,最复杂——无法提前预知某个object 是否已经变得无用。

 

对象的"活性":可达/ 不可达

 

静态区域的数据

 

Root包括:

–寄存器

–目前的执行栈中的

-数据所指向的内存对象

-活对象:从root 可达的对象

-死对象:从root 不可达

 

垃圾回收器根据对象的"活性"( 从root 的可达性) 来决定是否回收该对象的内存

"死"的对象就是需要回收的"垃圾"

 

GC的四种算法

1.Reference counting引用计数

引用计数的基本思想:为每个object 存储一 个计数RC ,当有其他reference 指向它时,RC++ ;当其他reference 与其断开时,RC-- ;如果RC==0,则回收它

引用计数方法的优点:简单、计算代价分散 ,"幽灵时间"短

缺点容易漏掉循环引用的对象

 

2.Mark-Sweep 标记

基本思想:为每个object设定状态位(live/dead)并记录,即mark阶段;将标记为dead的对象进行清理,即sweep可阶段。

优点:可以处理循环调用,指针操作无开销,对象不变

缺点:复杂度为O(heap),高 堆的占用比高时影响性能,容易造成碎片,需要找到root

 

3.Mark-Compact 标记-整理

基本思想将存活对象都向一端移动,然后清理掉端边界以外的内存。

优点:可以处理循环调用,指针操作无开销,对象不变

缺点:复杂度为O(heap),高 堆的占用比高时影响性能,容易造成碎片,需要找到root

 

4.Copying 复制

基本思想:为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。

优势:运行高效、不易产生内存碎片

缺点:复制花费大量的时间,牺牲内存空间

 

 

-verbose:gc"

使用该参数在控制台或日志文件中输出JVM进行GC的全过程

 

 

The permanent generation:java类元数据、interned String、类的静态变量

 

针对年轻代: 只有一小部分对象可较长时间存活,故采用copy 算法减少GC

针对年老代:这里的对象有很高的幸存度,使用Mark-Sweep 或Mark-Compact

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

 

针对young generation,使用minor GC 进行垃圾收集

Minor GC所需时间较短

如果历经多次minor GC仍存活下来,将其copy到old generation

如果old generation 满了,则启动full GC

当perm generation 满了之后,无法存储更多的元数据,也启动full GC

 

 

-XX: NewSize=<n>[g|m|k]

-XX: MaxNewSize=<n>[g|m|k]

-Xmn<n>[g|m|k]

-XX:NewRatio=<n>

-XX:SurvivorRatio=<n>

 

java –Xms 1024M –Xmx 2048M

 

 

System.gc()

 

GC模式选择

  • 增长或收缩年轻代或老年代的空间时需要Full GC
  • Full GC可能会降低吞吐量并导致超出期望的延迟
  • 串行收集器(-XX:+UseSerialGC):使用单个线程执行所有垃圾收集工作
  • 并行收集器(-XX:+UseParallelGC):并行执行Minor GC,显著减少垃圾收集开销
  • 并发低暂停收集器(-XX:+UseConcMarkSweepGC):收集持久代,与执行应用程序同时执行大部分收集,在收集期间会暂停一小段时间
  • 增量低暂停收集器(-XX:+UseTrainGC):收集每个Minor的部分老年代,并尽量减少Major的大停顿
  • -verbose:gc:打印GC信息

 

 

 

Dynamic Program Analysis

Java性能调优工具

  • Jstat:获取JVMHeap使用和GC的性能统计数据,命令如-gcutil
  • Jmap:输出内存中的对象分布情况  如:jmap -clstats
  • Jhat:导出heap dump,浏览/查询其中的对象分布情况
  • jstack:获取Java线程的stack trace 具体用途如下:
    • 定位线程出现长时间停顿的原因,如多线程间死锁、死循环、请求外部资源 导致的长时间等待等。
    • 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没 有响应的线程到底在后台做什么事情,或者等待什么资源。
  • Visual VM :提供了一个可视化界面,用于查看Java应用程序在JVM上运行时的详细信息,使用各种技术,包括jvmstatJMXServiceability AgentSA)和Attach API
  • MAT :内存堆导出文件的分析工具,生成饼状图等,能够对问题发生时刻的系统内存状态获取一个整体印象,找到最有可能导致内存泄露的对象,进一步查看其是否有异常行为。

 

静态分析:使用抽象的输入值

动态分析:要使用具体的输入值

 

 

 

 

 

-定位线程出现长时间停顿的原因,如多线程间死锁、死循环、请求外部资源

导致的长时间等待等。

线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

猜你喜欢

转载自www.cnblogs.com/masteryellow/p/9216154.html