《深入懂得Java虚拟机:JVM高级特性与最佳实践》勘误
《深入理解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'的十进制数字。上一次更新疏忽了,改了这页前面一句,还剩下这一句没有修改。
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。
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
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++”操作的。原本用哪个来演示都没问题,但是说明与代码不统一的确笔者疏忽所致。在下次重印时间将把代码修正为:
P366 字节码指令表中,bipush和sipush的数值范围应为(-128~127)和(-32768~32767),原文编辑时把负号漏掉了。
=========== 以下为已在第1次重印(2011.7.22)时修正的错误 ===========
P6:“并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.1也可以使用外挂方式的JIT编译器)”,这句话括号里面的内容有歧义,在重印的时候将修改为“并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.2中曾并存过3个虚拟机,Classic VM、HotSpot VM和Exact VM,其中Exact VM只在Solaris平台出现过;后面2个虚拟机都是内置JIT编译器的,而之前版本所带的Classic VM只能以外挂的形式使用JIT编译器)”
P9:脚注中“Hot Roekit”,应为“HotRockit”
P37:代码清单2-3的代码和2-2的代码完全一样,这是由于我工作疏忽而导致的粘贴错误,正确的代码2-3应为:
P51:“还可以使用-verbose:class以及-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载和卸载信息。”,这句话没有错误,但是重印的时候需要在后面补充说明一下:“-verbose:class和-XX:+TraceClassLoading可以在product版的虚拟机中使用,但是-XX:+TraceClassUnLoading参数需要fastdebug版的虚拟机支持。”
P82:“-XX:HeapDumpOnOutOfMemoryError参数、-XX:HeapDumpOnCtrlBreak参数”这2个参数都是开关参数,这里缺少加号。正确应为“-XX:+HeapDumpOnOutOfMemoryError参数、-XX:+HeapDumpOnCtrlBreak参数”
P141:表6-2,关于JDK 1.7中Javac的target默认参数,以前曾经是target 6,但很早(2009年8月左右)就修改回target 7了,所以表格倒数第三行的内容已经过时。重印时表格修改为下面这样:
P187:“<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序一定是先变量赋值再静态语句块(无论在源文件中出现的顺序如何),因此在静态语句块中可以访问到变量的初始值了”。这句话是错误的,在重印时将修改为:“<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。”
P364:倒数第4行的“Androd”应为“Android”。
(本帖我会随时保持更新,发现错误的同学,欢迎通过站内短信、Email等方式与我联系,本帖作为勘误公布,如有讨论,请移步至讨论帖)
我指的是当当,不知道作者您指的是哪家。
在这里可以买了,比当当还稍微便宜一些,感谢支持。http://product.china-pub.com/194035
《深入理解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; } }
P366 字节码指令表中,bipush和sipush的数值范围应为(-128~127)和(-32768~32767),原文编辑时把负号漏掉了。
=========== 以下为已在第1次重印(2011.7.22)时修正的错误 ===========
P6:“并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.1也可以使用外挂方式的JIT编译器)”,这句话括号里面的内容有歧义,在重印的时候将修改为“并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.2中曾并存过3个虚拟机,Classic VM、HotSpot VM和Exact VM,其中Exact VM只在Solaris平台出现过;后面2个虚拟机都是内置JIT编译器的,而之前版本所带的Classic VM只能以外挂的形式使用JIT编译器)”
P9:脚注中“Hot Roekit”,应为“HotRockit”
P37:代码清单2-3的代码和2-2的代码完全一样,这是由于我工作疏忽而导致的粘贴错误,正确的代码2-3应为:
/** * 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(); } }
P51:“还可以使用-verbose:class以及-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载和卸载信息。”,这句话没有错误,但是重印的时候需要在后面补充说明一下:“-verbose:class和-XX:+TraceClassLoading可以在product版的虚拟机中使用,但是-XX:+TraceClassUnLoading参数需要fastdebug版的虚拟机支持。”
P82:“-XX:HeapDumpOnOutOfMemoryError参数、-XX:HeapDumpOnCtrlBreak参数”这2个参数都是开关参数,这里缺少加号。正确应为“-XX:+HeapDumpOnOutOfMemoryError参数、-XX:+HeapDumpOnCtrlBreak参数”
P141:表6-2,关于JDK 1.7中Javac的target默认参数,以前曾经是target 6,但很早(2009年8月左右)就修改回target 7了,所以表格倒数第三行的内容已经过时。重印时表格修改为下面这样:
P187:“<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序一定是先变量赋值再静态语句块(无论在源文件中出现的顺序如何),因此在静态语句块中可以访问到变量的初始值了”。这句话是错误的,在重印时将修改为:“<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。”
P364:倒数第4行的“Androd”应为“Android”。
(本帖我会随时保持更新,发现错误的同学,欢迎通过站内短信、Email等方式与我联系,本帖作为勘误公布,如有讨论,请移步至讨论帖)
1 楼
bugu1986
2011-07-08
可是书还是预售中啊。。辛亏出差在外。。否则怎一个望眼欲穿了得啊。
2 楼
IcyFenix
2011-07-08
在china-pub可以买了。当当网不知道咋回事,一个星期了还在预售。
话说这个帖子要锁定掉才行,保持严肃,嗯嗯 。
话说这个帖子要锁定掉才行,保持严肃,嗯嗯 。
3 楼
bugu1986
2011-07-08
bugu1986 写道
可是书还是预售中啊。。辛亏出差在外。。否则怎一个望眼欲穿了得啊。
我指的是当当,不知道作者您指的是哪家。
4 楼
IcyFenix
2011-07-08
bugu1986 写道
我指的是当当,不知道作者您指的是哪家。
在这里可以买了,比当当还稍微便宜一些,感谢支持。http://product.china-pub.com/194035