主页

垃圾回收算法手册读书笔记(一)引言

引言 显式内存释放 vs 自动垃圾回收 几乎所有的语言都动态内存的分配,然而对于动态内存的回收,不同的语言与平台有着不同的机制。 其中C/C++采用显式的内存回收,允许程序员在显式的释放不再需要的对象。一方面显式内存释放可以使程序员获得更加细粒度的操作内存的能力,然而却会在另一方面增加程序出错的风险,例如过早回收对象导致的悬挂指针,以及忘记释放对象导致的内存泄漏,并且这两个问题在多线程环境下更为严重。开发者需要投入相当大的精力去精心处理内存相关的问题。 然而对于java等具备自动内存管理的平台,似乎不存在相关问题,垃圾回收机制的使用使得程序员不在需要关心一个对象在不再被使用后的释放工作,然而天下没有免费的午餐,开发人员普遍认为,垃圾回收通常会在内存吞吐量以及垃圾回收停顿时间方面引...

阅读更多

垃圾回收算法手册读书笔记(零) 开坑感言.

开坑感言 去年排查了一次Full GC 时间变长的问题,这个问题确实困扰了我一段时间,也上网找过不少文章和资料。大部分的文章与资料,包括一些书籍,仅是从某个语言入手,对特定语言相关的垃圾回收机制进行说明,看完之后仅仅是明白了该语言的垃圾回收是如何做的,却对为什么这样做不甚了解。 直到我接触《The Garbage Collection Cookbook》 (垃圾回收算法手册)这本书,这本书可以说是垃圾回收领域的经典著作之一,不仅解答了我的问题,让我对垃圾回收的各个方面有了新的认识,看完之后收益匪浅。该书并不针对于任何语言和平台,而是深入垃圾回收算法的原理,介绍了大量的垃圾回收算法的设计思路与原则。从最基本的垃圾回收器,到目前已经十分成熟的工业垃圾回收器,均有详细的介绍,是一本值得一读...

阅读更多

Full GC 时间变长的一次排查

问题背景 公司.net查询应用中有一个自实现的类似于 Guava Cache 的本地缓存管理组件,日常缓存项在10万到15万个之间。在一次改造后,添加了LRU缓存驱逐功能,实现的原理为经典的基于双链表的实现,即会维护一个包含所有缓存项的双链表,并按最近访问的先后顺序排序。问题在于功能上线后发现长耗时查询变多,对比原来翻了几倍,导致调用方超时报错变多。(绿线为发布时间点, 由图纵坐标可见超时异常最高达到9000) 排查过程 同事经过排查发现这些长耗时查询发生的时间点附近正好有Full GC发生,因此可以推断出这些长耗时查询是由于FuLL GC 的中断(stw)导致的。并且通过灰度下线一些机器的LRU缓存驱逐功能,比对有缓存驱逐功能和没有缓存驱逐功能的机器的差异,发现有缓存驱逐功能的...

阅读更多

延迟队列

定义 延迟队列中的每个元素都有一个过期时间,并且元素按照过期时间进行升序排序,队头元素的过期时间最近,当一个线程尝试从队列获取元素时候,只有队头元素过期才会出队,否则阻塞线程直到队头元素过期。 底层数据结构 延迟队列需要方便的获取当前剩余过期时间的元素,因此底层需要一个有序的数据结构来保存元素。优先队列可以满足我们的需要。以元素过期时间的远近作为评定优先的标准,近的元素优先于远的元素。根据优先队列的性质,优先队列队首的元素一定是过期时间最近的元素。 定义元素接口 定义元素的接口,延迟队列的元素必须有一个过期时间,因此元素必须提供一个方法获取剩余过期时间。定义Delayed接口,延迟队列的元素必须实现Delayed public interface Delayed { l...

阅读更多

优先队列

定义 相对于普通队列的先进先出,优先队列则是具有最高优先级的元素先出 底层数据结构 通常用过堆来实现 堆 堆是一个可以被看做一棵树的数组对象。并且满足下列性质: 堆总是一棵完全二叉树 堆中某个节点的值总是不大于(不小于)其父节点的值 其中,堆中某个节点的值总是不大于其父节点的值称为最大堆,反之为最小堆 堆的抽象结构(二叉树)与实际存储结构(数组) 抽象二叉树结构节点间的关系在实际数组结构中的映射 设当前节点的索引为n , 堆大小为 m 获取左子节点的索引 left = 2*n + 1 获取右子节点的索引 right = 2*n + 2 = left + 1 获取父节点的索引 parent = (n - 1) / 2 获取最后一个非叶子节点 i...

阅读更多

java并发编程基础

基于共享内存的并发编程 在基于共享内存的并发编程中,线程间通过读写共享的变量进行隐式的通信。在多线程并发读写共享变量的场景下,如果没有进行正确的同步,将会导致一些非预期的结果。 在编写正确的并发代码中,我们主要需要关注以下3个点 原子性:什么操作在什么条件下是原子的 可见性:一个线程对一个共享变量的写操作,写入的值在什么条件下,其它线程能够读到 有序性:在同一个线程内,代码的执行顺序看起来与编写的代码顺序一致。在正确同步下,一个线程(通过共享变量)观察另一个线程代码的执行顺序,看起来与编写的代码顺序一致 我们先看下面的case private static int a = 0; privat...

阅读更多