《深入理解Java虚拟机:JVM高级特性与最佳实践》勘误
《深入理解Java虚拟机:JVM高级特性与最佳实践》出版后收到不少读者的来信,热心地指出一些书中存在的缺陷,列出勘误如下:
前言的前面一页,第二段第7行,“虚拟机字节码的执行引擎以及它在实行代码时涉及的内存结构”,应为“执行”
P183 倒数第4行,“确认C是否有对D的访问权限”,应为“确认D是否有对C的访问权限”
P247 最后一行“会把其他进程向标准输出中打印的……”,应为线程。
P336 第一段“线程的创建、切换和调度都是需要考虑的问题”, 少了一个“的”
P346 “因为如果另一个线程恰好在错误的时间里删除了一个元素,导致序号i已经不再可用的话,get()方法就会抛出一个ArrayIndexOutOfBoundsException”,这个异常不限于get()方法,日志中演示的就是remove()方法,所有使用到那个已删除元素的方法都会出现异常。因此下一版中这句话会改为“因为如果另一个线程恰好在错误的时间里删除了一个元素,导致序号i已经不再可用的话,再用i访问数组就会抛出一个ArrayIndexOutOfBoundsException”
P62 “也就是当CPU在4个以上时,并发回收时垃圾收集线程最多占用不超过25%的CPU资源",这个推论有问题,正确的应该是“也就是当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源,并且随着CPU数量的增加而下降”
P213 “这时发生了两次自动类型转换,‘a’转型为整数65之后,进一步转型为长整数65L”,此处应为97, 65为'A'的十进制数字。上一次更新疏忽了,改了这页前面一句,还剩下这一句没有修改。
=========== 以下为已在第5次重印(2012.4.11)修正的错误 ===========
P64 “既能让使用者明确指定在一个长度为M毫秒的时间片段内”,错别字,应为“即”。
P93 代码清单4-7中最后3行排版有问题,漏掉了第一个字母:
br.readLine();
Object obj = new Object();
createLockThread(obj);
P213:'a'除了可以代表一个字符串外,还可以代表数字65(字符'a'的Unicode数值为十进制数字65),此处应为代表数字97, 65为'A'的十进制数字。
P225 倒数第三行“执行偏移地址为1的指令,istore_1指令……”,1是错误的,对应图8-6,应为“执行偏移地址为2的指令,”
P249 代码清单9-4
// 常量池中11种常量所占的长度
private static final int[] CONSTATN_ITEM_LENGTH = {-1, -1, 5, -1, 5, 9, 9, 3, 3, 5, 5, 5, 5};
正确的应为:
private static final int[] CONSTATN_ITEM_LENGTH = {-1, -1, -1, 5, 5, 9, 9, 3, 3, 5, 5, 5, 5};
P322 “执行sotre和write”,错别字,应为store。
=========== 以下为已在第4次重印(2011.12.6)修正的错误 ===========
P41 “程序使用了GCLib字节码增强”,错别字,应为“CGLIB”
P17 脚注:“JDK Plug已经不在需要了”,错别字,应为“不再”
P25 “它的作用可以看做是”,错别字,应为“看作”
P26 程序计数器的英文拼错,“Program Couter Register”,Counter少了个n,还有图中阴影部分,由所有线程共享的数据区应该包含“方法区”,“堆”。此问题只在第3、4次重印的图片中有,第1、2次印版的图是正确的,应是编辑重做图片时搞错了。
P123 “笔者测试了自己机器上的Tomcat和ClassFish启动过程”,错别字,应为GlassFish。
P128 “设置为-Xmx和-XX:PermSizeMax参数值一样”,错别字,应为MaxPermSize
P156 表6-14 2处“attribute_lenght”为错别字,应为attribute_length
P183 “由于无数据验证、字节码验证的需要”,错别字,应为“元数据验证”
P233-P234,“SharedClasLoader”为错别字,漏了一个s,应为“SharedClassLoader”,其中233页2处,234页1处
P235 最后一行“GlassFlish服务”,错别字,应为GlassFish。
P326 “java.util.concurrentb包”,“concurrent”后面多了一个“b”。
P328 “如果有多个进程共享一个并未声明为volatile的long或double类型的变量”,应为线程。
P333 “代码清单12-8的两条复制语句在同一个线程之中”,错别字,应为赋值语句。
P335 “所以各种进程操作,如创建、析构及同步”,应为线程。
P339 “12.4.3 状态转换”中,多处“线程”误写为“进程”,分别为:“Java语言定义了5种进程状态”……“一个进程只能有且只有其中的一种状态”……“处于这种状态的进程不会被分配CPU执行时间”……“处于这种状态的进程也不会被分配CPU执行时间”……“进程被阻塞了”。
P340 “限期等待(Timed Waitting)”,错别字,应为Waiting
=========== 以下为已在第3次重印(2011.9.29)修正的错误 ===========
P26 “每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息”,Operand译作“操作数”,本书其他地方也使用“操作数栈”的译法,这里笔误漏掉了红色的“数”字。另,也有译作“求值栈”,但本书未采用。
P26 “如果正在执行的是Natvie方法”,错别字,应为“Native”
P58 “不幸的是,它作为老年代的收集器”,有读者指出这里代词“它”似乎有歧义,可能会理解为它是“ParNew”,重印时将修改为“不幸的是,CMS作为老年代的收集器”。
P74 “以MaxTenuringThreshold = true参数来运行的结果”,应为“以HandlePromotionFailure = true参数来运行的结果”
P128 “从Old Gen曲线上看,永久代直接固定在384M”,这里有个笔误,应该是“老年代”。
P148 “access_flags中一共有32个标志位可以使用,当前只定义了其中8个”,32个是错误的,只有16个标志位可以用,因为access_flags的长度是u2。
P149 “是类级变量还是实例级变量(static修饰符)”,原本括号是注释整段话的,有朋友误解为注释“实例级变量”,那就把顺序换过来吧,改为“是实例变量还是类变量(static修饰符)”
P154 注释1中“<init>和<cinit>的详细内容见本书的第10章”。“<cinit>”应为“<clinit>”
P173 “对类进行发射调用的时候”,“发射”是错别字,应为“反射”。
P210 代码8-6倒数第5行的“StaticResolution sr = new StaticResolution();”,应为“StaticDispatch sd = new StaticDispatch();”
P354 代码清单13-5,代码说明中写的方法名字是incrementAndGet(),而代码中所使用的则是getAndIncrement()。这2个方法是原子类用于对应 “++i”和“i++”操作的。原本用哪个来演示都没问题,但是说明与代码不统一的确笔者疏忽所致。在下次重印时间将把代码修正为:
/** * Atomically increment by one the current value. * @return the updated value */ public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }/** * VM Args:-Xss2M * @author zzm */public class JavaVMStackOOM { private void dontStop() { while (true) { } } public void stackLeakByThread() { while (true) { Thread thread = new Thread(new Runnable() { @Override public void run() { dontStop(); } }); thread.start(); } } public static void main(String[] args) throws Throwable { JavaVMStackOOM oom = new JavaVMStackOOM(); oom.stackLeakByThread(); }}