- 浏览: 940173 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
hw7777777:
非常感谢作者提供这么好的工具,在使用的过程中遇到一些问题?1、 ...
基于java nio的memcached客户端——xmemcached -
SINCE1978:
多久过去了时间能抹平一切
无路用的人 -
fangruanyjq:
[img][/img]引用
用osworkflow写一个请假例子(提供代码下载) -
thinkingmysky:
楼主,你确定,java memached client能处理并 ...
memcached java client性能测试的几点疑问和说明 -
hellostory:
aaa5131421 写道07年2月hibernate已经出来 ...
dozer与BeanUtils
第一个程序:
import java.util.ArrayList; import java.util.List; public class TailRecursionTest { public static void main(String[] args) { TailRecursionTest t = new TailRecursionTest(); for (int i = 0; i < 10000; i++) t.a(0); } public void a(int j) { j++; List list = new ArrayList<Integer>(100000); // 对list进行处理 } }
没啥特殊的,仅仅是为了测试,我们将a方法调用10000次,a方法创建一个有100000个元素的list的局部变量。
第二个程序:
import java.util.ArrayList; import java.util.List; public class TailRecursionTest2 { public static void main(String[] args) { TailRecursionTest2 t = new TailRecursionTest2(); t.a(0); } public void a(int j) { System.out.println(j); j++; if (j == 10000) return; List list = new ArrayList<Integer>(100000); // 对list进行处理 a(j); } }
也没啥特殊的,就是将循环换成了递归,a方法做的事情没变。两个都跑一下,程序1顺利结束,程序2出问题了,啥问题?如下:
161 162 163 164 165 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.ArrayList.<init>(Unknown Source) at TailRecursionTest2.a(TailRecursionTest2.java:17) at TailRecursionTest2.a(TailRecursionTest2.java:20) at TailRecursionTest2.a(TailRecursionTest2.java:20) at TailRecursionTest2.a(TailRecursionTest2.java:20) at TailRecursionTest2.a(TailRecursionTest2.java:20)
我倒,才运行166次了,heap就满了。问题在哪呢?oh,yep,你肯定想到了,是不是重复创建list这个大集合引起的呢?它不是局部变量吗?怎么 也会溢出?是的,list是局部变量,在a的方法栈里引用着,指向heap上的大对象,更关键的问题在于,java是没有尾递归优化的,递归方法是不会使 用同一个栈帧,每一次递归调用,都将压入新的栈帧,并且这个栈帧上又new了一个list变量,引用着heap上新的一个大集合。随着栈深度的增加, jvm里维持着一条长长的方法调用轨迹以便你能回来,在方法没有返回之前,这些list变量一直被各自的栈帧引用着,不能被GC,你说,能不OOM吗?
也许,你想到了个补救方法来挽救程序2,就是每次在处理完list后,我把它设置为null,不让栈帧继续引用着它,咱编写对gc友好的代码,这不就行了,试试:
import java.util.ArrayList; import java.util.List; public class TailRecursionTest2 { public static void main(String[] args) { TailRecursionTest2 t = new TailRecursionTest2(); t.a(0); } public void a(int j) { System.out.println(j); j++; if (j == 10000) return; List list = new ArrayList<Integer>(100000); // 对list进行处理 list = null; //gc友好 a(j); } }
得意洋洋,我跑一下看看,这次跑到4000多次,但是:
...... 4289 4290 4291 4292 java.lang.StackOverflowError at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source) at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source) at java.nio.charset.CharsetEncoder.encode(Unknown Source)
没办法啊,人家sun的jdk就是不支持尾递归优化(据说传闻在jdk5的某个版本是有尾递归优化的),很不给你面子的栈溢出了。ibm的jdk据说支持尾递归优化,上面这个程序在ibm的jdk上可能可以正常结束,未经测试。
总结:在java里,递归最好咱还是别用,老老实实地while、for;就算递归了,最好递归方法不要new太大的对象,除非你能确定递归的深度不是那么大,否则OOM和堆栈溢出的阴影将笼罩着你。
评论
JDK不做尾部递归优化是有他的道理的。
如果采用递归优化,显然有两条途径:
1.在静态编译阶段做该优化。
这样做的后果就是导致编译后的class字节码的语义发生了改变。就是从class文件反编译得不到原来的源代码了。
2.在JIT阶段做该优化。
这样可以避免编译过程中代码语义的变化。
但会有其他问题,比较易见的一个是:如果在递归的某一层该方法抛出了一个异常,显然没做优化之前的堆栈轨迹与优化之后的堆栈轨迹是不一样的。
再比如下面这段代码:
public class TailRecursionTest { private static int loop(int i) { return loop(i); } public static void main(String[] args) { loop(0); } }
尾部优化之后应该是:
public class TailRecursionTest { private static int loop(int i) { while (true) { } } public static void main(String[] args) { loop(0); } }
显然两段代码运行的结果不一样了:第一段会导致堆栈溢出,而第二段能一直运行下去。
1、你说的第一点,貌似sun在jdk1.4还是1.5的编译器可以做尾递归优化,我一个同事那时候还做过测试,通过javap观察是通过invokedynamic指令实现的,现在用1.6再看,编译后的指令已经改成了invokestatic,去掉了尾递归优化。就语义的改变而言,我不认为有那么重要?需要反编译的场景很多吗?
2、嗯,这是个问题,可能在debug查错上做出误导。
就你举的代码例子,如果有尾递归优化,第一个程序不会堆栈溢出,行为其实跟程序2是一致的,尽管结构不一样。
楼上说在jdk6上程序2是可以正常的结束,可以证明ibm的jdk6是支持尾递归优化的,不知道是编译期优化,还是jit优化?又是基于何种考虑允许这种优化?
这个bug是2002年提出的,讲的就是这件事。
没办法啊,人家sun的jdk就是不支持尾递归优化(据说传闻在jdk5的某个版本是有尾递归优化的),很不给你面子的栈溢出了。ibm的jdk据说支持尾递归优化,上面这个程序在ibm的jdk上可能可以正常结束,未经测试。
总结:在java里,递归最好咱还是别用,老老实实地while、for;就算递归了,最好递归方法不要new太大的对象,除非你能确定递归的深度不是那么大,否则OOM和堆栈溢出的阴影将笼罩着你。
JDK不做尾部递归优化是有他的道理的。
如果采用递归优化,显然有两条途径:
1.在静态编译阶段做该优化。
这样做的后果就是导致编译后的class字节码的语义发生了改变。就是从class文件反编译得不到原来的源代码了。
2.在JIT阶段做该优化。
这样可以避免编译过程中代码语义的变化。
但会有其他问题,比较易见的一个是:如果在递归的某一层该方法抛出了一个异常,显然没做优化之前的堆栈轨迹与优化之后的堆栈轨迹是不一样的。
再比如下面这段代码:
public class TailRecursionTest { private static int loop(int i) { return loop(i); } public static void main(String[] args) { loop(0); } }
尾部优化之后应该是:
public class TailRecursionTest { private static int loop(int i) { while (true) { } } public static void main(String[] args) { loop(0); } }
显然两段代码运行的结果不一样了:第一段会导致堆栈溢出,而第二段能一直运行下去。
# at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source)
# at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)
# at java.nio.charset.CharsetEncoder.encode(Unknown Source)
文章很好,但是最后面的错误面显是堆栈溢出吖,又不是oom
是丫,我说了是堆栈溢出了 结论再改下。
# at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source)
# at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)
# at java.nio.charset.CharsetEncoder.encode(Unknown Source)
文章很好,但是最后面的错误面显是堆栈溢出吖,又不是oom
发表评论
-
memcached分布测试报告(一致性哈希情况下的散列函数选择)
2009-03-10 16:30 8546一、背景资料 memcached本身是集中式的缓存系统 ... -
xmemcached 0.60 优化过程
2009-03-06 14:37 3523充分利用jprofile等 ... -
Xmemcached vs Spymemcached 3th(linux下测试结果和多节点下表现)
2009-03-07 10:43 4882翠花,上图,首先是容器类和自定义对象的get、set在不同并发 ... -
xmemcached发布1.0-BETA版
2009-03-09 15:32 4122xmemcached 发布1.0-beta ,从0.6 ... -
山寨nio框架yanf4j发布0.50-alpha
2009-02-04 19:28 4223俺的山寨nio框架yanf4j发布0.50-alpha版本,下 ... -
yanf4j引入了客户端非阻塞API
2009-02-19 00:15 3118yanf4j 发布一个0.50-beta2 版本,这个版本最 ... -
基于java nio的memcached客户端——xmemcached
2009-03-03 16:31 74761、xmemcached是什么? xmemcached是基于 ... -
使用yanf4j写个简单聊天室
2008-11-26 11:36 5399yanf4j 简介,请看这里 ... -
Java字符串的最大长度
2009-01-15 01:37 7585在cpp中为了可移植性,s ... -
yanf4j-0.41 beta发布
2009-01-20 14:01 1866项目名称:yanf4j (yet another nio fr ... -
再谈Selector的wakeup方法
2009-02-01 11:15 3052过去推荐过两篇blog《Java NIO类库Selector机 ... -
Yet another nio framework for java
2008-10-11 14:25 2047项目名称:Yanf4j(Yet another nio fra ... -
阻塞队列的性能对比
2008-09-08 10:06 5746阻塞队列的性能对 ... -
java package的设计原则
2008-09-06 00:15 2118典型的J2EE项目,package的设计有成熟的套路可 ... -
线程池池
2008-09-01 19:39 1998这个题目比较怪,听俺道来。俺一直在负责公司游戏服 ... -
第一个MapReduce任务
2008-08-23 11:10 2784前两天在公司内网上搭了个2个节点hadoop集群, ... -
从HDFS看分布式文件系统的设计需求
2008-08-15 22:39 8119分布式文件系统的 ... -
HDFS用户指南(翻译)
2008-08-14 20:27 2141HDFS用户指南 原文地址:http:/ ... -
Ehcache配置的overflowToDisk属性
2008-08-06 23:18 10838Ehcache的overflowToDisk属性用来配 ... -
工作的几个tip
2008-07-07 20:47 28861、如果用java6的ScriptEngineManager ...
相关推荐
在Java代码中,我们通常会创建`HSSFWorkbook`或`XSSFWorkbook`对象来表示Excel工作簿,`HSSFSheet`或`XSSFSheet`对象来代表工作簿内的工作表,然后通过`HSSFRow`和`XSSFRow`以及`HSSFCell`和`XSSFCell`来操作行和...
根据给定的信息,本文将对20个非常有用的Java代码片段进行详细解析,这些代码片段不仅涵盖了基础的数据类型转换、文件处理,还包括了日期格式化、数据库操作等实用功能。 ### 1. 整型数字转字符串与字符串转整型...
这个名为"java新手代码适合初学者简单经典.zip"的压缩包包含了两个示例文件:test1.java和test2.java,它们很可能是为帮助初学者理解Java编程基础而设计的一些简单程序。 1. **Java基础** - **变量与数据类型**:...
下面,我们将深入探讨这个Java代码的工作原理、涉及的知识点以及如何进行扩展。 首先,我们看到一个名为`HeartShape`的公共类,它包含一个`main`方法,这是Java程序的入口点。在`main`方法中,我们定义了一个变量`...
### Java代码优化技巧详解 #### 一、引言 在软件开发过程中,为了提升应用程序的性能,我们需要对Java代码进行优化。这是因为计算机系统的资源(如内存、CPU时间、网络带宽等)是有限的,而优化的目标就是使程序...
根据提供的文件信息,可以看出这是一段不完整的 Java 代码,主要涉及了 Java 中的基本界面构建、菜单栏设计以及按钮操作等内容。接下来将基于这段代码的关键部分进行知识点的梳理与总结。 ### Java GUI 基础 #### ...
在Android开发中,JavaScript(JS)与Java代码的相互调用是常见的需求,尤其是在混合式应用开发中。这种交互能够充分利用JavaScript的灵活性和Java的强大功能,实现更丰富的用户体验。本Demo旨在提供一个清晰、易懂...
给定的文件信息提供了一个Java代码示例,用于实现MD5哈希算法,下面将详细解析这段代码,并深入探讨MD5算法在Java中的应用。 ### MD5算法简介 MD5(Message-Digest Algorithm 5)是RSA数据安全公司设计的一种散列...
"解析PDM生成POJO(Java代码生成器)"是一个这样的工具,它可以帮助开发者自动化创建JavaBean和HBM(Hibernate Mapping File)类,这两个是Java后端开发中的重要组成部分。本文将深入探讨这个主题,讲解相关知识点。...
Java代码重构是一种优化编程实践,旨在改进代码的结构和可读性,而不改变其外部行为。重构对于提高软件质量和维护性至关重要,尤其是在大型项目中。以下是一些在Java重构中的关键原则和技巧,通过实例来展示如何应用...
这暗示了工具可能包含两个核心功能:一是将SQL语句转换为Java代码,二是帮助生成字符串拼接的Java代码。在Java中,有多种方式可以实现字符串拼接,比如使用`+`操作符,但当拼接的字符串数量较多时,这种方式的效率较...
总的来说,C++/Java代码分析器是一款强大的工具,它将C++和Java这两种广泛使用的编程语言的解析能力集成在一起,为用户提供了一个全面了解和优化代码的平台。无论是为了学习还是提高工作效率,这款分析器都值得...
《2048游戏Java代码解析》 2048是一款简单却又极具挑战性的数字合成游戏,由意大利开发者Gabriele Cirulli于2014年推出。在这个游戏中,玩家需要通过滑动屏幕,使得相同的数字合并成更大的数字,最终目标是达到2048...
【Java实现聊天室代码详解】 Java作为一种广泛使用的编程语言,其强大的网络编程能力使得开发聊天室应用程序变得简单而高效。本篇文章将详细讲解如何利用Java编写一个基于GUI界面的服务器和客户端聊天程序。 首先...
【极光推送后台Java代码Demo】是针对极光推送服务的一个示例代码,它展示了如何在Java后端环境中集成和使用极光推送服务。极光推送(JPush)是一款广泛应用于移动应用开发中的消息推送服务,它允许开发者向Android、...
本文将围绕一个简单的Java代码片段进行深入解析,旨在揭示其背后的逻辑、应用场景以及可能的扩展思路,从而为读者提供一份详实的知识点总结。 ### 代码片段解读 #### 原始代码: ```java if(!"".equals(addrName) ...
【标题】:“Java代码适合学习” Java是一种广泛使用的高级编程语言,以其“一次编写,到处运行”的特性闻名。它在跨平台应用开发中占据主导地位,尤其在企业级软件、移动应用(尤其是Android)、Web应用以及云计算...
这段Java代码创建了一个简单的加法计算器。它使用了Java Swing库来构建图形用户界面(GUI),包括输入框(JTextField)、标签(JLabel)、按钮(JButton)以及面板(JPanel)。程序的核心是实现了ActionListener接口...
以下是一些关键的Java代码方法和相关知识点: 1. **字符串操作**: - `String` 类提供了多种方法,如 `length()`(获取字符串长度)、`substring()`(截取子字符串)、`indexOf()`(查找子串位置)和 `replace()`...
同时,使用注释来解释关键代码段的功能,有助于他人理解你的代码。 总的来说,这个Java五子棋游戏项目为初学者提供了一个实践基础编程概念和技能的机会。通过分析和实现这个游戏,学习者可以提升对Java语言的理解,...