Full GC

Stop the world, clean your mind.


  • 首页

  • 归档

深入理解Java虚拟机学习笔记(三)

发表于 2017-09-17 | 更新于 2019-03-27

Hotspot VM的实现

  1. OopMap:在类加载完成后记录下对象内的数据类型与偏移量,在JIT编译过程中记录下栈和寄存器中哪些位置是引用。
  2. 安全点:在指令序列复用时,如方法调用,循环跳转,异常跳转等。
  3. 中断:
    • 抢先式中断:不需要线程代码配合,当GC发生时,先把所有线程都中断,如果发现线程中断的点不在安全点上,则恢复线程,让他跑到安全点上。
    • 主动式中断:当GC需要中断线程的时候,在安全点上设置中断标志,线程执行时主动轮询中断标志,发现标志为真时则主动中断挂起线程。
  4. 安全区域:指线程在某一段代码片段中,引用关系不会发生变化,在这个区域中的任意点开始GC都是安全的。在线程处于blocked或sleep状态无法跑到安全点时,采用安全区域可以避免GC长时间等待。

垃圾收集器

  1. Serial收集器:单线程,进行垃圾收集时必须暂停所有工作线程。Client模式下默认新生代收集器。采用复制算法。优点:简单高效,进行垃圾收集时不需要与工作线程交互。缺点:必须暂停所有工作线程,停顿时间较长。
  2. Serial Old收集器:Serial收集器的老年代版本。主要也是在Client模式下使用,在Server模式下,主要与Parallel Scavenge收集器搭配使用,或作为CMS收集器的后备预案。采用标记-整理算法。
  3. ParNew收集器:Serial收集器的多线程版本,除了能够多线程进行垃圾收集以外,其他与Serial收集器相似,进行垃圾收集时必须暂停所有工作线程。Server模式下默认新生代收集器。采用复制算法。在CPU核心数量较多的时候垃圾收集效率较高,但在CPU核心数量较少的时候效率不一定比Serial收集器高。
  4. Parallel Scavenge收集器:与ParNew类似,也是多线程收集器,但更关注于达到一个可控制的吞吐量(用于执行用户代码的CPU时间与CPU总消耗时间的比值)。采用复制算法。
  5. Parallel Old收集器:Parallel Scavenge的老年代版本。采用标记-整理算法。
  6. CMS收集器:并发收集器,追求最短回收停顿时间,适合追求服务响应速度的服务端应用。采用标记-清除算法。优点:收集过程中耗时最长的步骤都可以和用户工作线程并发工作。缺点:对CPU资源非常敏感,在CPU核心数较少的情况下,对应用的运行速度有较大影响;无法处理浮动垃圾,即在垃圾收集过程中总有新的垃圾不断产生,只能积累到下一次GC再收集;标记-清除算法容易导致产生大量内存碎片,从而提前触发Full GC。
  7. G1收集器:并行与并发;分代收集;空间整合;可预测的停顿。使用Region划分GC堆。
阅读全文 »

深入理解Java虚拟机学习笔记(二)

发表于 2017-09-16 | 更新于 2019-03-27

垃圾收集器与内存分配策略

对象的生存与死亡

引用计数与可达性分析算法

  1. 引用计数:当对象被引用时,计数器+1;当引用失效时,计数器-1。效率高,但无法解决循环引用的问题。
  2. 可达性分析:以GC Root为起始点,向下搜索,搜索走过的路径称为引用链,当从GC Root到对象不可达时,该对象为孤立对象,即可回收。
    • GC Root:
      • 虚拟机栈(栈帧中的局部变量表)中引用的对象
      • 方法区中类静态属性引用的对象
      • 方法区中常量引用的对象
      • 本地方法栈中JNI引用的对象

引用强度

  1. 强引用:程序代码中普遍存在的,如使用new操作符产生的引用。只要强引用还存在,系统将不会回收被强引用的对象。
  2. 软引用:SoftReference类实现,用来描述一些还有用但是并非必需的对象。当系统将要发生内存溢出时,软引用对象将被列入可回收的范围内并进行二次回收,若回收后仍然没有足够的内存,系统才会抛出内存溢出异常。
  3. 弱引用:WeakReference类实现,用来描述非必需对象。无论内存是否足够,弱引用对象都只能生存到发生下一次垃圾收集之前。
  4. 虚引用:PhantomReference类实现,仅用于在对象被回收时得到通知。虚引用完全不影响对象的生存时间,也无法通过虚引用来获取一个对象实例。
阅读全文 »

深入理解Java虚拟机学习笔记(一)

发表于 2017-09-14 | 更新于 2019-03-27

内存区域与内存溢出异常

运行时数据区域

  1. 程序计数器:线程私有,负责指令跳转,执行Java方法时记录虚拟机字节码指令地址,执行Native方法时为空。
  2. 虚拟机栈:线程私有,存储栈帧。
    • 栈帧:方法运行时的基础数据结构,方法执行时创建,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
    • 局部变量表:由若干个局部变量空间(Slot)组成,存放编译器可知的基本数据类型,对象的引用和返回地址类型,其中64位整数long和浮点数double的数据会占用2个空间(Slot),其余数据类型只占用一个。局部变量表的内存空间是在编译时完成分配的,在方法运行期间不会发生改变。
  3. 本地方法栈:规范中无强制规定,在Hotspot VM中与虚拟机栈合二为一。
  4. 堆:线程共享,虚拟机启动时创建,存放对象实例。也叫GC堆。
  5. 方法区:线程共享,存放虚拟机加载的类,常量,静态变量,JIT编译后的代码等数据。
  6. 运行时常量池:方法区的一部分,存放编译期生成的各种字面量和符号引用。
  7. 直接内存:不属于运行时数据区域,通过NIO类通过Native函数库直接分配堆外内存。
阅读全文 »

【译】正确使用密码加盐散列

发表于 2016-01-31 | 更新于 2019-03-27

如果你是一个 web 开发工程师,可能你已经建立了一个用户账户系统。一个用户账户系统最重要的部分是如何保护密码。用户账户数据库经常被黑,如果你的网站曾经被攻击过,你绝对必须做点什么来保护你的用户的密码。最好的用来保护密码的方式是采用加盐密码散列 (salted password hasing)。 本文将解释为什么要这样做。

互联网上充斥着大量的误导信息,有许许多多的关于如何正确做密码散列的矛盾的观点,有些甚至是误解。密码散列是一个简单的事情,但是仍然有很多人做错了。在这篇文章中,我不仅将解释正确实现的方式,而且告诉你为什么这样做。

重要提示:如果你正在试图自己编码实现密码散列,请停下来!它太容易搞糟了。不,不,不,你在大学上的密码学课程不能让你避免这个警告。这个警告适用于每个人:不要实现自己的加密!如何保存密码的问题已经被解决了。使用 phpass 或者本文后面提供的代码。

如果因为什么原因你没有阅读上面的警告,请现在立即去读一遍。真的,本文不是教你如何实现自己的密码存储系统,而是解释为什么密码应该这样存储。

本文后面有基于 BSD 授权协议的密码散列源代码:

  • PHP 源代码
  • Java 源代码
  • ASP.NET(C#) 源代码
  • Ruby (on Rails) 源代码
阅读全文 »
12
Hans

Hans

14 日志
3 标签
GitHub E-Mail
© 2019 Hans
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Gemini v7.0.1