pstack

pstack http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/pstack.html pstack 跟踪进程栈 此命令可显示每个进程的栈跟踪。pstack 命令必须由相应进程的属主或 root 运行。可以使用 pstack 来确定进程挂起的位置。此命令允许使用的唯一选项是要检查的进程的 PID。请参见 proc(1) 手册页。 这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态 (如假死状态,好似死循环) ,使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方; 示例: 查看bash程序进程栈: /opt/app/tdev1$ps -fe| grep bash tdev1 7013 7012 0 19:42 pts/1 00:00:00 -bash tdev1 11402 11401 0 20:31 pts/2 00:00:00 -bash tdev1 11474 11402 0 20:32 pts/2 00:00:00 grep bash /opt/app/tdev1$pstack 7013 #0 0x00000039958c5620 in __read_nocancel () from /lib64/libc.so.6 #1 0x000000000047dafe in rl_getc () #2 0x000000000047def6 in rl_read_key () #3 0x000000000046d0f5 in readline_internal_char () ...

2017-06-10 · 1 min · 116 words · -

strace, 跟踪进程中的系统调用

strace, 跟踪进程中的系统调用 sudo pacman -S strace 统计系统调用的耗时 strace -cp <PID> http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/strace.html strace 跟踪进程中的系统调用 strace 常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。 输出参数 每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 strace 显示这些调用的参数并返回符号形式的值。strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。 strace cat /dev/null execve("/bin/cat", [“cat”, “/dev/null”], [/* 22 vars */]) = 0 brk(0) = 0xab1000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f29379a7000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) … 参数 -c 统计每一系统调用的所执行的时间,次数和出错的次数等. -d 输出strace关于标准错误的调试信息. -f 跟踪由fork调用所产生的子进程. -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号. -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪. -h 输出简要的帮助信息. -i 输出系统调用的入口指针. ...

2017-06-08 · 1 min · 205 words · -

CPU 使用率, 服务器负载

CPU 使用率, 服务器负载 http://www.jianshu.com/p/e134b8498413 load average: 系统平均负载是 CPU 的L oad, 它所包含的信息不是 CPU 的使用率状况, 而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数之和的统计信息, 也就是 CPU 使用队列的长度的统计信息, 这个数字越小越好。 CPU 负载和 CPU 使用率的区别 CPU 使用率: 显示的是程序在运行期间实时占用的 CPU 百分比 CPU 负载: 显示的是一段时间内正在使用和等待使用 CPU 的平均任务数 CPU使用率高, 并不意味着负载就一定大。 举例来说: 如果我有一个程序它需要一直使用CPU的运算功能,那么此时CPU的使用率可能达到100%,但是CPU的工作负载则是趋近于"1",因为CPU仅负责一个工作嘛!如果同时执行这样的程序两个呢?CPU的使用率还是100%,但是工作负载则变成2了。所以也就是说,当CPU的工作负载越大,代表CPU必须要在不同的工作之间进行频繁的工作切换。 举例说明: 网上有篇文章举了一个有趣比喻,拿打电话来说明两者的区别,我按自己的理解阐述一下。 某公用电话亭,有一个人在打电话,四个人在等待,每人限定使用电话一分钟,若有人一分钟之内没有打完电话,只能挂掉电话去排队,等待下一轮。电话在这里就相当于CPU,而正在或等待打电话的人就相当于任务数。 在电话亭使用过程中,肯定会有人打完电话走掉,有人没有打完电话而选择重新排队,更会有新增的人在这儿排队,这个人数的变化就相当于任务数的增减。为了统计平均负载情况,我们5分钟统计一次人数,并在第1、5、15分钟的时候对统计情况取平均值,从而形成第1、5、15分钟的平均负载。 有的人拿起电话就打,一直打完1分钟,而有的人可能前三十秒在找电话号码,或者在犹豫要不要打,后三十秒才真正在打电话。如果把电话看作CPU,人数看作任务,我们就说前一个人(任务)的CPU利用率高,后一个人(任务)的CPU利用率低。 当然, CPU并不会在前三十秒工作,后三十秒歇着,只是说,有的程序涉及到大量的计算,所以CPU利用率就高,而有的程序牵涉到计算的部分很少,CPU利用率自然就低。 结论: 无论CPU的利用率是高是低,跟后面有多少任务在排队没有必然关系。 负载为多少才算比较理想? 这个有争议,各有各的说法,个人比较赞同CPU负载小于等于0.5算是一种理想状态。 不管某个CPU的性能有多好,1秒钟能处理多少任务,我们可以认为它无关紧要,虽然事实并非如此。在评估CPU负载时,我们只以5分钟为单位为统计任务队列长度。如果每隔5分钟统计的时候,发现任务队列长度都是1,那么CPU负载就为1。假如我们只有一个单核的CPU,负载一直为1,意味着没有任务在排队,还不错。 但是我那台服务器,是双核双CPU,等于是有4个内核,每个内核的负载为1的话,总负载为4。这就是说,如果我那台服务器的CPU负载长期保持在4左右,还可以接受。 但是每个内核的负载为1,并不能算是一种理想状态!这意味着我们的CPU一直很忙,不得清闲。网上有说理想的状态是每个内核的负载为0.7左右,我比较赞同,0.7乘以内核数,得出服务器理想的CPU负载,比如我这台服务器,负载在3.0以下就可以。 如何来降低服务器的CPU负载? 最简单办法的是更换性能更好的服务器,不要想着仅仅提高CPU的性能,那没有用,CPU要发挥出它最好的性能还需要其它软硬件的配合。 在服务器其它方面配置合理的情况下,CPU数量和CPU核心数(即内核数)都会影响到CPU负载,因为任务最终是要分配到CPU核心去处理的。两块CPU要比一块CPU好,双核要比单核好。 因此,我们需要记住,除去CPU性能上的差异,CPU负载是基于内核数来计算的!有一个说法,“有多少内核,即有多少负载”。 CPU使用率到多少才算比较理想? CPU使用率长时间60-80%就认为机器有瓶颈出现。 2.load average 多少是正常? 既然load是cpu计算的队列,那就应该和cpu个处理方式和cpu的个数有关系。所以我个人认为应该按系统识别的cpu个数来确定load的临界值,系统识别为8个cpu,那么load为8就是临界点,高于8就属于over load了。 什么叫系统识别CPU个数? 这里涉及到cpu物理个数和超线程技术的问题。对于单处理器在满负载的情况下1.00,则双处理器的负载满额的情况是 2.00,它还有一倍的资源可以利用。从性能的角度上理解,一台主机拥有多核心的处理器与另台拥有同样数目的处理性能基本上可以认为是相差无几。当然实际 情况会复杂得多,不同数量的缓存、处理器的频率等因素都可能造成性能的差异。但即便这些因素造成的实际性能稍有不同,其实系统还是以处理器的核心数量计算负载均值 。这使我们有了两个新的法则: ...

2017-06-08 · 1 min · 92 words · -

Parallel Scavenge

Parallel Scavenge Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量 (Throughput) 。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间) ,虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户的体验;而高吞吐量则可以最高效率地利用CPU时间,尽快地完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。 Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数及直接设置吞吐量大小的 -XX:GCTimeRatio参数。 MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过设定值。不过大家不要异想天开地认为如果把这个参数的值设置得稍小一点就能使得系统的垃圾收集速度变得更快,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的: 系统把新生代调小一些,收集300MB新生代肯定比收集500MB快吧,这也直接导致垃圾收集发生得更频繁一些,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次、每次停顿70毫秒。停顿时间的确在下降,但吞吐量也降下来了。 GCTimeRatio参数的值应当是一个大于0小于100的整数,也就是垃圾收集时间占总时间的比率,相当于是吞吐量的倒数。如果把此参数设置为19,那允许的最大GC时间就占总时间的5% (即1 / (1+19) ) ,默认值为99,就是允许最大1% (即1 / (1+99) ) 的垃圾收集时间。 由于与吞吐量关系密切,Parallel Scavenge收集器也经常被称为"吞吐量优先"收集器。除上述两个参数之外,Parallel Scavenge收集器还有一个参数-XX:+UseAdaptiveSizePolicy值得关注。这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小 (-Xmn) 、Eden与Survivor区的比例 (-XX:SurvivorRatio) 、晋升老年代对象年龄 (-XX:PretenureSizeThreshold) 等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略 (GC Ergonomics) 。如果读者对于收集器运作原理不太了解,手工优化存在困难的时候,使用Parallel Scavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个很不错的选择。只需要把基本的内存数据设置好 (如-Xmx设置最大堆) ,然后使用MaxGCPauseMillis参数 (更关注最大停顿时间) 或GCTimeRatio参数 (更关注吞吐量) 给虚拟机设立一个优化目标,那具体细节参数的调节工作就由虚拟机完成了。自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。 HotSpot VM里多个GC有部分共享的代码。有一个分代式GC框架,Serial/Serial Old/ParNew/CMS都在这个框架内;在该框架内的young collector和old collector可以任意搭配使用,所谓的"mix-and-match"。 而ParallelScavenge与G1则不在这个框架内,而是各自采用了自己特别的框架。这是因为新的GC实现时发现原本的分代式GC框架用起来不顺手。请参考官方文档的Collector Styles一段。 ParallelScavenge (PS) 的young collector就如其名字所示,是并行的拷贝式收集器。本来这个young collector就是"Parallel Scavenge"所指,但因为它不兼容原本的分代式GC框架,为了凸显出它是不同的,所以它的young collector带上了PS前缀,全名变成PS Scavenge。对应的,它的old collector的名字也带上了PS前缀,叫做PS MarkSweep。 这个PS MarkSweep默认的实现实际上是一层皮,它底下真正做mark-sweep-compact工作的代码是跟分代式GC框架里的serial old (这个collector名字叫做MarkSweepCompact) 是共用同一份代码的。也就是说实际上PS MarkSweep与MarkSweepCompact在HotSpot VM里是同一个collector实现,包了两张不同的皮;这个collector是串行的。 ...

2017-06-05 · 1 min · 153 words · -

java, jvm GC

java, jvm GC STW (Stop the World) 悬挂指针 查看当前使用的 GC jmx JMX 查看当前JVM使用的GC MBean java.lang.GarbageCollector java code 输出结果跟JMX查看的结果相同. import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.util.List; public class TestGC { public static void main(String args[]) { List<GarbageCollectorMXBean> l = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean b : l) { System.out.println(b.getName()); } } } prod gc: Copy MarkSweepCompact // 输出 Copy, MarkSweepCompact 代表正在使用单线程的垃圾回收器 -XX:+UseSerialGC 名词解释: 在 GC 的世界里对象指的是通过应用程序利用的数据的集合。是 GC 的基本单位。一般由头 (header) 和域 (field) 构成。 ...

2017-06-04 · 5 min · 866 words · -

Garbage-First G1

Garbage-First G1 http://ifeve.com/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3g1%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8/ G1 GC是Jdk7的新特性之一、Jdk7+版本都可以自主配置G1作为JVM GC选项;作为JVM GC算法的一次重大升级、DK7u后G1已相对稳定、且未来计划替代CMS、所以有必要深入了解下: 不同于其他的分代回收算法、G1将堆空间划分成了互相独立的区块。每块区域既有可能属于O区、也有可能是Y区,且每类区域空间可以是不连续的 (对比CMS的O区和Y区都必须是连续的) 。这种将O区划分成多块的理念源于: 当并发后台线程寻找可回收的对象时、有些区块包含可回收的对象要比其他区块多很多。虽然在清理这些区块时G1仍然需要暂停应用线程、但可以用相对较少的时间优先回收包含垃圾最多区块。这也是为什么G1命名为Garbage First的原因: 第一时间处理垃圾最多的区块。 平时工作中大多数系统都使用CMS、即使静默升级到JDK7默认仍然采用CMS、那么G1相对于CMS的区别在: G1在压缩空间方面有优势 G1通过将内存空间分成区域 (Region) 的方式避免内存碎片问题 Eden, Survivor, Old区不再固定、在内存使用效率上来说更灵活 G1可以通过设置预期停顿时间 (Pause Time) 来控制垃圾收集时间避免应用雪崩现象 G1在回收内存后会马上同时做合并空闲内存的工作、而CMS默认是在STW (stop the world) 的时候做 G1会在Young GC中使用、而CMS只能在O区使用 就目前而言、CMS还是默认首选的GC策略、可能在以下场景下G1更适合: 服务端多核CPU、JVM内存占用较大的应用 (至少大于4G) 应用在运行过程中会产生大量内存碎片、需要经常压缩空间 想要更可控、可预期的GC停顿周期;防止高并发下应用雪崩现象

2017-06-04 · 1 min · 37 words · -

程序,进程, 线程, 内核线程, 轻量级进程, 用户线程

程序,进程, 线程, 内核线程, 轻量级进程, 用户线程 程序 程序用于描述进程要完成的功能,是控制进程执行的指令集; 数据集合是程序在执行时所需要的数据和工作区; 程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的唯一标志。 进程 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的; 并发性:任何进程都可以同其他进程一起并发执行; 独立性:进程是系统进行资源分配和调度的一个独立单位; 结构性:进程由程序、数据和进程控制块三部分组成。 Linux进程类别 虽然我们在区分Linux进程类别, 但是我还是想说Linux下只有一种类型的进程,那就是task_struct,当然我也想说linux其实也没有线程的概念, 只是将那些与其他进程共享资源的进程称之为线程。 一个进程由于其运行空间的不同, 从而有内核线程和用户进程的区分, 内核线程运行在内核空间, 之所以称之为线程是因为它没有虚拟地址空间, 只能访问内核的代码和数据, 而用户进程则运行在用户空间, 但是可以通过中断, 系统调用等方式从用户态陷入内核态。 用户进程运行在用户空间上, 而一些通过共享资源实现的一组进程我们称之为线程组, Linux下内核其实本质上没有线程的概念, Linux下线程其实上是与其他进程共享某些资源的进程而已。但是我们习惯上还是称他们为线程或者轻量级进程 因此, Linux上进程分3种,内核线程 (或者叫核心进程)、用户进程、用户线程, 当然如果更严谨的,你也可以认为用户进程和用户线程都是用户进程。 关于轻量级进程这个概念, 其实并不等价于线程 不同的操作系统中依据其实现的不同, 轻量级进程其实是一个不一样的概念 内核进程 内核中没有进程的概念 不存在的概念, 内核空间的进程共享内核空间的内存, 没有独立的地址空间, 不能算是进程, 所以没有内核进程这个概念. https://www.coder.work/article/6802420 内核中没有进程的概念,所以你的问题没有意义。 Linux 内核可以并且确实创建了完全在内核上下文中运行的线程,但是所有这些线程都运行在相同的地址空间中。尽管相关线程通常具有相关名称,但没有按 PID 对类似线程进行分组。 如果多个内核线程正在处理同一任务或以其他方式共享数据,则它们需要通过锁定或其他并发算法来协调对该数据的访问。当然,内核中不提供 pthreads API,但是可以使用内核互斥锁、等待队列等来获得与 pthread 互斥锁、条件变量等相同的功能。 将这些执行上下文称为“内核线程”是一个相当不错的名字,因为它们非常类似于用户空间进程中的多个线程。它们都共享(内核的)地址空间,但有自己的执行上下文(堆栈、程序计数器等),并且每个都被独立调度并并行运行。另一方面,内核实际上实现了所有漂亮的 POSIX API 抽象(在用户空间中的 C 库的帮助下),因此在该实现的内部我们没有完整的抽象。 内核线程 内核线程一般特指由内核自己启动的只运行在内核态的一些服务进程. 只运行在内核态 ps命令输出里名字带中括号 内核线程也可以叫内核任务,它们周期性地执行例如,磁盘高速缓存的刷新,网络连接的维护,页面的换入换出等等。 内核线程执行的是内核中的函数,而普通进程只有通过系统调用才能执行内核中的函数。 内核线程只运行在内核态,而普通进程既可以运行在用户态,也可以运行在内核态。 因为内核线程指只运行在内核态,因此,它只能使用大于PAGE_OFFSET (3G)的地址空间。另一方面,不管在用户态还是内核态,普通进程可以使用4GB的地址空间。 内核线程是由kernel_thread( )函数在内核态下创建的 内核线程和用户进程的区分, 内核线程运行在内核空间, 之所以称之为线程是因为它没有虚拟地址空间 内核线程就是内核的分身,一个分身可以处理一件特定事情。这在处理异步事件如异步IO时特别有用。内核线程的使用是廉价的,唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核(Multi-Threads kernel )。 ...

2017-06-02 · 13 min · 2746 words · -

System.gc(), System.runFinalization()

System.gc(), System.runFinalization() System.gc: 告诉垃圾收集器打算进行垃圾收集,而垃圾收集器进不进行收集是不确定的。只是建议进行回收。 jvm有自己的gc策略,不建议手动调用。 system.gc其实是做一次full gc system.gc会暂停整个进程 system.gc一般情况下我们要禁掉,使用-XX:+DisableExplicitGC system.gc在cms gc下我们通过-XX:+ExplicitGCInvokesConcurrent来做一次稍微高效点的GC(效果比Full GC要好些) system.gc最常见的场景是RMI/NIO下的堆外内存分配等 System.runFinalization() Runs the finalization methods of any objects pending finalization. Calling this method suggests that the Java Virtual Machine expend effort toward running the finalize methods of objects that have been found to be discarded but whose finalize methods have not yet been run. When control returns from the method call, the Java Virtual Machine has made a best effort to complete all outstanding finalizations. ...

2017-06-02 · 1 min · 98 words · -

JNI左中括号[B[C[[C等

‘JNI左中括号[B[C[[C等’ http://blog.csdn.net/qinjuning/article/details/7599796 在Java存在两种数据类型: 基本类型 和 引用类型 。 在JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下: 1、primitive types ----基本数据类型,如: int、 float 、char等基本类型 2、reference types----引用类型,如: 类、实例、数组。 特别需要注意: 数组 ------ 不管是对象数组还是基本类型数组,都作为reference types存在。 1、primitive types (基本数据类型)映射参见下表: 这些基本数据类型都是可以在Native层直接使用的 。 2、reference types (引用数据类型)映射参见下表 Java类型 Native Type 描述 注意: 1、引用数据类型则不能直接使用,需要根据JNI函数进行相应的转换后,才能使用 2、多维数组(包括二维数组)都是引用类型,需要使用 jobjectArray 类型存取其值 ; 例如: 二维整型数组就是指向一位数组的数组,其声明使用方式如下: print? //获得一维数组 的类引用,即jintArray类型 jclass intArrayClass = env->FindClass("[I"); //构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为dimion jobjectArray obejctIntArray = env->NewObjectArray(dimion ,intArrayClass , NULL); ...//具体操作 另外,关于引用类型的一个继承关系如下,我们可以对具有父子关系的类型进行转换: 类描述符 类描述符是类的完整名称 (包名+类名) ,将原来的 . 分隔符换成 / 分隔符。 例如: 在java代码中的java.lang.String类的类描述符就是java/lang/String 其实,在实践中,我发现可以直接用该类型的域描述符取代,也是可以成功的。 例如: jclass intArrCls = env->FindClass("java/lang/String") 等同于 jclass intArrCls = env->FindClass("Ljava/lang/String;") 数组类型的描述符则为,则为: [ + 其类型的域描述符 (后文说明) 例如: int [ ] 其描述符为[I float [ ] 其描述符为[F String [ ] 其描述符为[Ljava/lang/String; 域描述符 1、基本类型的描述符已经被定义好了,如下表所示: 2、引用类型的描述符 一般引用类型则为 L + 该类型类描述符 + ; (注意,这儿的分号";"只得是JNI的一部分,而不是我们汉语中的分段,下同) 例如: String类型的域描述符为 Ljava/lang/String; 对于数组,其为 : [ + 其类型的域描述符 + ; int[ ] 其描述符为[I float[ ] 其描述符为[F String[ ] 其描述符为[Ljava/lang/String; Object[ ]类型的域描述符为[Ljava/lang/Object; 多维数组则是 n个[ +该类型的域描述符 , N代表的是几维数组。例如: int [ ][ ] 其描述符为[[I float[ ][ ] 其描述符为[[F 方法描述符 将参数类型的域描述符按照申明顺序放入一对括号中后跟返回值类型的域描述符,规则如下: (参数的域描述符的叠加)返回 类型描述符。对于,没有返回值的,用V(表示void型)表示。举例如下: Java层方法 JNI函数签名 String test ( ) Ljava/lang/String; int f (int i, Object object) (ILjava/lang/Object;)I void set (byte[ ] bytes) ([B)V 在编程时,如果是利用javah工具的话,这些都不需要我们手动编写对应的类型转换,如果不能用javah工具,就只能手动的 进行类型转换了。

2017-06-02 · 1 min · 169 words · -

java8 去除 永久代, metaspace (元空间)

java8 去除 永久代, metaspace (元空间) 在过去 (当自定义类加载器使用不普遍的时候) ,类几乎是"静态的"并且很少被卸载和回收, 因此类也可以被看成"永久的"。另外由于类作为JVM实现的一部分,它们不由程序来创建,因为它们也被认为是"非堆"的内存。 在JDK8之前的 HotSpot虚拟机中,类的这些"永久的"数据存放在一个叫做永久代的区域。永久代一段连续的内存空间,我们在JVM启动之前可以通过设置-XX:MaxPermSize 的值来控制永久代的大小, 32位机器默认的永久代的大小为64M, 64位的机器则为85M。永久代的垃圾回收和老年代的垃圾回收是绑定的,一旦其中一个区域被占满, 这两个区都要进行垃圾回收。但是有一个明显的问题, 由于我们可以通过‑XX:MaxPermSize 设置永久代的大小,一旦类的元数据超过了设定的大小, 程序就会耗尽内存,并出现内存溢出错误(OOM)。 备注: 在JDK7之前的 HotSpot虚拟机中, 纳入字符串常量池的字符串被存储在永久代中, 因此导致了一系列的性能问题和内存溢出错误。 http://www.cnblogs.com/moonandstar08/p/5001914.html 这项改动是很有必要的, 因为对永久代进行调优是很困难的。 永久代中的元数据可能会随着每一次 Full GC发生而进行移动。并且为永久代设置空间大小也是很难确定的, 因为这其中有很多影响因素,比如类的总数,常量池的大小和方法数量等。 同时,HotSpot 虚拟机的每种类型的垃圾回收器都需要特殊处理永久代中的元数据。将元数据从永久代剥离出来, 不仅实现了对元空间的无缝管理, 还可以简化Full GC以及对以后的并发隔离类元数据等方面进行优化。 新增加的 metaspace (元空间) 持久代的空间被彻底地删除了, 它被一个叫元空间的区域所替代了。 持久代删除了之后,很明显, JVM会忽略 PermSize 和 MaxPermSize 这两个参数,还有就是你再也看不到 java.lang.OutOfMemoryError: PermGen error 的异常了。 JDK 8 的 HotSpot JVM 现在使用的是本地内存来表示类的元数据,这个区域就叫做元空间。 元空间存储类的元信息,静态变量和常量池等并入堆中。相当于永久代的数据被分到了堆和元空间中。 元空间的特点: 充分利用了Java语言规范中的好处: 类及相关的元数据的生命周期与类加载器的一致。 每个加载器有专门的存储空间 只进行线性分配 不会单独回收某个类 省掉了GC扫描及压缩的时间 元空间里的对象的位置是固定的 如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉 元空间的内存分配模型 绝大多数的类元数据的空间都从本地(native)内存中分配 用来描述类元数据的类也被删除了 分元数据分配了多个虚拟内存空间 给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些 归还内存块,释放内存块列表 一旦元空间的数据被清空了,虚拟内存的空间会被回收掉 减少碎片的策略 ...

2017-06-02 · 1 min · 78 words · -

/dev/shm

/dev/shm http://dbua.iteye.com/blog/1271574 1.linux下的/dev/shm是什么? /dev/shm/是linux下一个目录,/dev/shm目录不在磁盘上,而是在内存里,因此使用linux /dev/shm/的效率非常高,直接写进内存。 我们可以通过以下两个脚本来验证linux /dev/shm的性能: [root@db1 oracle]# ls -l linux_11gR2_grid.zip -rw-r-r- 1 oracle dba 980831749 Jul 11 20:18 linux_11gR2_grid.zip [root@db1 oracle]# cat mycp.sh !/bin/sh echo date cp linux_11gR2_grid.zip .. echo date [root@db1 oracle]# ./mycp.sh Fri Jul 15 18:44:17 CST 2011 Fri Jul 15 18:44:29 CST 2011 [root@db1 shm]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rootvg-lv01 97G 9.2G 83G 10% / /dev/sda1 99M 15M 80M 16% /boot ...

2017-05-31 · 5 min · 979 words · -

sar command

sar command sar -n DEV 1 sar -n TCP,ETCP 1 Cannot open /var/log/sa/sa22: No such file or directory 22 是指当天的日期 这个是由于没有创建那sa22这个文件,这可以通过参数-o让其生成 sar -o 2 3 在对应的/var/log/sa/目录下就有对应的日志文件了 在运行就不会报错了 还有另外一种情况,因为刚刚装上sar所以还没有数据在/var/log/sa/sa22下,因为sar -n DEV 默认是是过去十分钟的系统活动报告。 pacman -S sysstat sar 找出系统瓶颈的利器 sar是System Activity Reporter (系统活动情况报告) 的缩写。sar工具将对系统当前的状态进行取样,然后通过计算数据和比例来表达系统的当前运行状态。它的特点是可以连续对系统取样,获得大量的取样数据;取样数据和分析的结果都可以存入文件,所需的负载很小。sar是目前Linux上最为全面的系统性能分析工具之一,可以从14个大方面对系统的活动进行报告,包括文件的读写情况、系统调用的使用情况、串口、CPU效率、内存使用状况、进程活动及IPC有关的活动等,使用也是较为复杂。 sar是查看操作系统报告指标的各种工具中,最为普遍和方便的;它有两种用法; 追溯过去的统计数据 (默认) 周期性的查看当前数据 12.1. 追溯过去的统计数据 默认情况下,sar从最近的0点0分开始显示数据;如果想继续查看一天前的报告;可以查看保存在/var/log/sysstat/下的sa日志; 使用sar工具查看: $sar -f /var/log/sysstat/sa28 | head sar -r -f /var/log/sysstat/sa28 ../_images/sar1.png 12.2. 查看CPU使用率 sar -u : 默认情况下显示的cpu使用率等信息就是sar -u; ../_images/sar2.png 可以看到这台机器使用了虚拟化技术,有相应的时间消耗; 各列的指标分别是: %user 用户模式下消耗的CPU时间的比例; %nice 通过nice改变了进程调度优先级的进程,在用户模式下消耗的CPU时间的比例 %system 系统模式下消耗的CPU时间的比例; ...

2017-05-30 · 2 min · 291 words · -

busybox

busybox BusyBox 是一个提供了很多简化版的Unix 工具的一个可执行文件, busybox能在很多POSIX环境运行,比如Linux,Android,FreeBSD. BusyBox最初是由布鲁斯·斐伦斯在1996年为Debian GNU/Linux安装光盘而编写 Busybox只提供每个工具程序的简化版 (例如: ls指令不提供排序功能) 。 BusyBox 是一个集成了一百多个最常用linux命令和工具的软件,他甚至还集成了一个http服务器和一个telnet服务器,而所有这一切功能却只有区区1M左右的大小。BusyBox 包含了一些简单的工具,比如: 我们平时用的那些linux命令就好比是分立式的电子元件,而busybox就好比是一个集成电路,把常用的工具和命令集成压缩在一个可执行文件里,功能基本不变,而大小却小很多倍,例如ls、 cat 和 echo等等,还包含了一些更大、更复杂的工具,例如 grep、find、mount 以及telnet。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令,也包含了 Android 系统自带的shell。BusyBox 将许多具有共性的小版本的UNIX工具结合到一个单一的可执行文件。这样的集合可以替代大部分常用工具比如: GNU 等工具,BusyBox提供了一个比较完善的环境,可以适用于任何小的或嵌入式系统。在嵌入式linux应用中,busybox有非常广的应用,另外,大多数linux发行版的安装程序中都有busybox的身影,安装linux的时候案ctrl+alt+F2可以切换物理终端,而这个物理终端中的所有命令都是指向busybox的链接.Busybox虽小,但作用确是惊人的,这样就可以基于Busybox制作一张软盘linux。 http://jilili.blog.51cto.com/6617089/1170368 https://busybox.net/ https://en.wikipedia.org/wiki/BusyBox

2017-05-27 · 1 min · 30 words · -

java 监视器

java 监视器 http://ifeve.com/monitors-java-synchronization-mechanism/ 监视器–JAVA同步基本概念 大学有一门课程叫操作系统,学习过的同学应该都记得,监视器是操作系统实现同步的重要基础概念,同样它也用在JAVA的线程同步中,这篇文章用一种类推的思想解释监视器"monitor"。 1.什么是监视器 监视器可以看做是经过特殊布置的建筑,这个建筑有一个特殊的房间,该房间通常包含一些数据和代码,但是一次只能一个消费者(thread)使用此房间, Java-Monitor 当一个消费者(线程)使用了这个房间,首先他必须到一个大厅(Entry Set)等待,调度程序将基于某些标准(e.g. FIFO)将从大厅中选择一个消费者(线程),进入特殊房间,如果这个线程因为某些原因被"挂起",它将被调度程序安排到"等待房间",并且一段时间之后会被重新分配到特殊房间,按照上面的线路,这个建筑物包含三个房间,分别是"特殊房间"、“大厅"以及"等待房间”。 java-monitor-associate-with-object 简单来说,监视器用来监视线程进入这个特别房间,他确保同一时间只能有一个线程可以访问特殊房间中的数据和代码。 2.JAVA中监视器的实现 在JAVA虚拟机中,每个对象(Object和class)通过某种逻辑关联监视器,为了实现监视器的互斥功能,每个对象(Object和class)都关联着一个锁(有时也叫"互斥量"),这个锁在操作系统书籍中称为"信号量",互斥(“mutex “)是一个二进制的信号量。 如果一个线程拥有了某些数据的锁,其他的线程则无法获得锁,直到这个线程释放了这个锁。在多线程中,如果任何时候都是我们自己来写这个信号量,显然不是很方便,幸运的是,JVM为我们自动实现了这些。 为了使数据不被多个线程访问,java 提供了同步块 以及 同步方法两种实现,一旦一段代码被嵌入到一个synchronized关键字中,意味着放入了监视区域,JVM在后台会自动为这段代码实现锁的功能。 3.JAVA的同步代码中,哪一部分是监视器? 我们知道JAVA每个对象(Object/class) 都关联一个监视器,更好的说法应该是每个对象(Object/class)都有一个监视器,对象可以有它自己的临界区,并且能够监视线程序列为了使线程协作,JAVA为提供了wait()和notifyAll以及notify()实现挂起线程,并且唤醒另外一个等待的线程,此外这些方法有三种不同版本: wait(long timeout, int nanos) wait(long timeout) notified by other threads or notified by timeout. notify(all) 这些方法只能在一个同步块或同步方法中被调用,原因是,如果一个方法不需要相互排斥,不需要监测或线程之间协作,每一个线程可以自由访问此方法,那就不需要协作。

2017-05-25 · 1 min · 40 words · -

hbase BufferedMutator

hbase BufferedMutator org.apache.hadoop.hbase.client.BufferedMutator主要用来对HBase的单个表进行操作。它和Put类的作用差不多,但是主要用来实现批量的异步写操作。 BufferedMutator替换了HTable的setAutoFlush(false)的作用。 可以从Connection的实例中获取BufferedMutator的实例。在使用完成后需要调用close()方法关闭连接。对BufferedMutator进行配置需要通过BufferedMutatorParams完成。 MapReduce Job的是BufferedMutator使用的典型场景。MapReduce作业需要批量写入,但是无法找到恰当的点执行flush。BufferedMutator接收MapReduce作业发送来的Put数据后,会根据某些因素 (比如接收的Put数据的总量) 启发式地执行Batch Put操作,且会异步的提交Batch Put请求,这样MapReduce作业的执行也不会被打断。 BufferedMutator也可以用在一些特殊的情况上。MapReduce作业的每个线程将会拥有一个独立的BufferedMutator对象。一个独立的BufferedMutator也可以用在大容量的在线系统上来执行批量Put操作,但是这时需要注意一些极端情况比如JVM异常或机器故障,此时有可能造成数据丢失。

2017-05-22 · 1 min · 12 words · -

堆内内存, 堆外内存

堆内内存, 堆外内存 一、什么是堆外内存 堆内内存 (on-heap memory) 回顾 堆外内存和堆内内存是相对的二个概念,其中堆内内存是我们平常工作中接触比较多的,我们在jvm参数中只要使用-Xms,-Xmx等参数就可以设置堆的大小和最大值,理解jvm的堆还需要知道下面这个公式: 堆内内存 = 新生代+老年代+持久代 如下面的图所示: Paste_Image.png 在使用堆内内存 (on-heap memory) 的时候,完全遵守JVM虚拟机的内存管理机制,采用垃圾回收器 (GC) 统一进行内存管理,GC会在某些特定的时间点进行一次彻底回收,也就是Full GC,GC会对所有分配的堆内内存进行扫描,在这个过程中会对JAVA应用程序的性能造成一定影响,还可能会产生Stop The World。 常见的垃圾回收算法主要有: 引用计数器法 (Reference Counting) 标记清除法 (Mark-Sweep) 复制算法 (Coping) 标记压缩法 (Mark-Compact) 分代算法 (Generational Collecting) 分区算法 (Region) 注: 在这里我们不对各个算法进行深入介绍,感兴趣的同学可以关注我的下一篇关于垃圾回收算法的介绍分享。 堆外内存 (off-heap memory) 介绍 和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理 (而不是虚拟机) ,这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。 作为JAVA开发者我们经常用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用,它会在对象创建的时候就分配堆外内存。 DirectByteBuffer类是在Java Heap外分配内存,对堆外内存的申请主要是通过成员变量unsafe来操作,下面介绍构造方法 DirectByteBuffer(int cap) { super(-1, 0, cap, cap); //内存是否按页分配对齐 boolean pa = VM.isDirectMemoryPageAligned(); //获取每页内存大小 int ps = Bits.pageSize(); //分配内存的大小,如果是按页对齐方式,需要再加一页内存的容量 long size = Math.max(1L, (long)cap + (pa ? ps : 0)); //用Bits类保存总分配内存(按页分配)的大小和实际内存的大小 Bits.reserveMemory(size, cap); long base = 0; try { //在堆外内存的基地址,指定内存大小 base = unsafe.allocateMemory(size); } catch (OutOfMemoryError x) { Bits.unreserveMemory(size, cap); throw x; } unsafe.setMemory(base, size, (byte) 0); //计算堆外内存的基地址 if (pa && (base % ps != 0)) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); att = null; } 注: 在Cleaner 内部中通过一个列表,维护了一个针对每一个 directBuffer 的一个回收堆外内存的 线程对象(Runnable),回收操作是发生在 Cleaner 的 clean() 方法中。 ...

2017-05-17 · 3 min · 470 words · -

CLH队列,CLH锁

CLH队列,CLH锁 CLH的发明人是: Craig,Landin and Hagersten。 CLH锁即 Craig, Landin, and Hagersten (CLH) locks CLH锁是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。 CLH锁是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。 CLH算法实现 CLH队列锁表示为QNode对象的链表,QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁。结点之间是通过隐形的链表相连,之所以叫隐形的链表是因为这些结点之间没有明显的next指针,每个线程通过一个线程局部变量pred指向其前驱,线程通过检测前驱结点的locked域来判断是否轮到自己。如果该域为true,则前驱线程要么已经获得锁要么正在等待锁;如果该域为false,则前驱进程已释放锁,轮到自己了。正常情况下,队列链中只有一个结点的locked域为false。CLHLock上还有一个尾指针,始终指向队列的最后一个结点。 当一个线程调用lock()方法想获得锁时,将自己的locked域置为true,表示该线程不准备释放锁,然后并将自己的结点加入到队列链尾部。最后就是在前驱的locked域上旋转,等待前驱释放锁。当这个线程调用unlock()方法要释放锁时,线程要将自己的locked域置为false,表示已经释放锁,然后将前驱结点作为自己的新结点以便日后访问。 //clh 1 class ClhSpinLock { private final ThreadLocal<Node> prev; private final ThreadLocal<Node> node; private final AtomicReference<Node> tail = new AtomicReference<Node>(new Node()); public ClhSpinLock() { this.node = new ThreadLocal<Node>() { protected Node initialValue() { return new Node(); } }; this.prev = new ThreadLocal<Node>() { protected Node initialValue() { return null; } }; } public void lock() { final Node node = this.node.get(); node.locked = true; // 一个CAS操作即可将当前线程对应的节点加入到队列中, // 并且同时获得了前继节点的引用,然后就是等待前继释放锁 Node pred = this.tail.getAndSet(node); this.prev.set(pred); while (pred.locked) {// 进入自旋 } } public void unlock() { final Node node = this.node.get(); node.locked = false;// 改变状态,让后续线程结束自旋 this.node.set(this.prev.get()); } private static class Node { private volatile boolean locked; } } //clh 2 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class CLHLock { public static class CLHNode { private volatile boolean isLocked = true; // 默认是在等待锁 } @SuppressWarnings("unused" ) private volatile CLHNode tail ; private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater .newUpdater(CLHLock.class, CLHNode .class , "tail" ); public void lock(CLHNode currentThread) { CLHNode preNode = UPDATER.getAndSet( this, currentThread); if(preNode != null) {//已有线程占用了锁,进入自旋 while(preNode.isLocked ) { } } } public void unlock(CLHNode currentThread) { // 如果队列里只有当前线程,则释放对当前线程的引用 (for GC) 。 if (!UPDATER.compareAndSet(this, currentThread, null)) { // 还有后续线程 currentThread.isLocked = false ;// 改变状态,让后续线程结束自旋 } } } NUMA与SMP SMP ( Symmetric Multi-Processor ) , 对称多处理器结构 对称多处理器结构,指服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。SMP的优点是能够保证内存一致性,缺点是这些共享的资源很可能成为性能瓶颈,随着CPU数量的增加,每个CPU都要访问相同的内存资源,可能导致内存访问冲突,可能会导致CPU资源的浪费。常用的PC机就属于这种。 ...

2017-05-17 · 2 min · 230 words · -

Java8 jdeps

Java8 jdeps http://blog.csdn.net/u013803262/article/details/70570161 Java8中带了一个新的类依赖分析器。 我们可以在Java的安装目录的bin目录下看到jdeps.exe这个文件。 这个工具是用于分析类的依赖关系的。 具体怎么用 可以这样。 找一个目录,下面全是jar文件。那么这样的目录很明显WEB-INF下的lib目录就非常合适。 假设我们有一个web项目,tomcat下的lib有 commons-pool2-2.0.jar jedis-2.5.1.jar 为了使得结构简单点。我们只加入了两个jar包并且jedis包依赖于commons-pool这个包。 我们进入lib目录下运行命令 jdeps *.jar 结果得到 E:\git_tmp\distributedSession\target\distributedSession\WEB-INF\lib>jdeps *.jar commons-pool2-2.0.jar -> F:\Program Files\Java\jdk1.8.0_121\jre\lib\rt.jar commons-pool2-2.0.jar -> 找不到 org.apache.commons.pool2 (commons-pool2-2.0.jar) -> java.io -> java.lang -> java.util -> java.util.concurrent.locks org.apache.commons.pool2.impl (commons-pool2-2.0.jar) -> java.io -> java.lang -> java.lang.management -> java.lang.ref -> java.lang.reflect -> java.security -> java.text -> java.util -> java.util.concurrent -> java.util.concurrent.atomic -> java.util.concurrent.locks -> javax.management -> org.apache.commons.pool2 commons-pool2-2.0.jar org.apache.commons.pool2.proxy (commons-pool2-2.0.jar) -> java.lang -> java.lang.reflect ...

2017-05-17 · 1 min · 151 words · -

Deprecate HTablePool

Deprecate HTablePool https://issues.apache.org/jira/browse/HBASE-6580 http://blog.csdn.net/jiyiqinlovexx/article/details/36526433 http://blog.csdn.net/u010967382/article/details/38046821

2017-05-16 · 1 min · 5 words · -

HBase的WAL机制 WAL (Write-Ahead-Log)

HBase的WAL机制 WAL (Write-Ahead-Log) WAL机制解析 WAL(Write-Ahead Logging)是一种高效的日志算法,几乎是所有非内存数据库提升写性能的不二法门,基本原理是在数据写入之前首先顺序写入日志,然后再写入缓存,等到缓存写满之后统一落盘。之所以能够提升写性能,是因为WAL将一次随机写转化为了一次顺序写加一次内存写。提升写性能的同时,WAL可以保证数据的可靠性,即在任何情况下数据不丢失。假如一次写入完成之后发生了宕机,即使所有缓存中的数据丢失,也可以通过恢复日志还原出丢失的数据。 WAL持久化等级 HBase中可以通过设置WAL的持久化等级决定是否开启WAL机制、以及HLog的落盘方式。WAL的持久化等级分为如下四个等级: SKIP_WAL: 只写缓存,不写HLog日志。这种方式因为只写内存,因此可以极大的提升写入性能,但是数据有丢失的风险。在实际应用过程中并不建议设置此等级,除非确认不要求数据的可靠性。 ASYNC_WAL: 异步将数据写入HLog日志中。 SYNC_WAL: 同步将数据写入日志文件中,需要注意的是数据只是被写入文件系统中,并没有真正落盘。 FSYNC_WAL: 同步将数据写入日志文件并强制落盘。最严格的日志写入等级,可以保证数据不会丢失,但是性能相对比较差。 USER_DEFAULT: 默认如果用户没有指定持久化等级,HBase使用SYNC_WAL等级持久化数据。 用户可以通过客户端设置WAL持久化等级,代码: put.setDurability(Durability. SYNC_WAL ); HLog数据结构 HBase中,WAL的实现类为HLog,每个Region Server拥有一个HLog日志,所有region的写入都是写到同一个HLog。下图表示同一个Region Server中的3个 region 共享一个HLog。当数据写入时,是将数据对<HLogKey,WALEdit>按照顺序追加到HLog中,以获取最好的写入性能。 WAL(Write-Ahead-Log)预写日志是HBase的RegionServer在处理数据插入和删除的过程中用来记录操作内容的一种日志。在每次Put、Delete等一条记录时,首先将其数据写入到RegionServer对应的HLog文件的过程。 客户端往RegionServer端提交数据的时候,会先写WAL日志,只有当WAL日志写成功以后,客户端才会被告诉提交数据成功,如果写WAL失败会告知客户端提交失败,换句话说这其实是一个数据落地的过程。 在一个RegionServer上的所有的Region都共享一个HLog,一次数据的提交是先写WAL,写入成功后,再写memstore。当memstore值到达一定是,就会形成一个个StoreFile (理解为HFile格式的封装,本质上还是以HFile的形式存储的) 。 HLog类 RegionServer内WAL文件与Region的关系图 WAL的实现类是HLog,当一个Region被初始化的时候,一个HLog的实例会作为构造函数的参数传进去。 当Region在处理Put、Delete等更新操作时,可以直接使用该共享的HLog的append方法来落地数据。 Put、Delete在客户端上可以通过setWriteToWAL(false)方法来关闭该操作的日志,这么做虽然可以提升入库速度,但最好别这么做,因为有数据丢失的风险存在。 http://www.zkread.com/article/69288.html http://hbasefly.com/2016/03/23/hbase_writer/

2017-05-09 · 1 min · 40 words · -