<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tim[后端技术] &#187; Java</title>
	<atom:link href="http://timyang.net/category/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://timyang.net</link>
	<description>Tim&#039;s blog, 关于后端架构、互联网技术、分布式、大型网络应用、NoSQL、Key Value等</description>
	<lastBuildDate>Mon, 02 Aug 2010 15:34:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>使用脚本引擎增加程序运行时动态执行能力(Java篇)</title>
		<link>http://timyang.net/java/java-scripting/</link>
		<comments>http://timyang.net/java/java-scripting/#comments</comments>
		<pubDate>Mon, 18 May 2009 11:30:33 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://timyang.net/?p=174</guid>
		<description><![CDATA[对于非Web的后台服务程序，经常会碰到这样的需求：

动态改变程序运行时参数的能力。如Config.limitValue = 50
动态查看运行时候变量状态的能力，如 print(userMap.size())
执行代码的能力，如 userMap.clear()

对于需求1,非Web的程序没法像PHP/JSP那样直接改就生效，往往改了某个值，即使是一个配置参数都需要服务器重启一下。这对于很多线上服务来说成本太高。
对于上述2的需求，通常是编写庞大的后台管理程序来满足。或者是通过增加日志输出，但问题是某些变量只需要偶尔才看一下，因此很多系统中大部分日志开销基本上是无用的。
对于需求3,只有通过在IDE的debug模式下才能达到。
我觉得所有的后台程序都应该具备这样的能力，为了满足以上需求，于是考虑在所有程序里面嵌入一个小型的解释脚本引擎来实现。就像很多游戏程序嵌入Lua/Python来动态执行代码目的一样。
今天先说下Java中的实现方法，几年前用过BeanShell, 可以在Java VM里面解释执行多种类型脚本语言。但是发现已经多年不更新，原来是Java 6已经内建Scripting的支持，所以这些第三方的工具也都结束了历史使命。
Java 6自带的实际上是 Mozilla Rhino 的Java Script引擎，它使用JavaScript的语法，可以调用任意Java代码。更多介绍见Java Scripting Programmer&#8217;s Guide. Rhino除了import写法有点特殊外，基本语法和Java代码基本一致。如：
engine.eval("importClass(java.lang.System)");
engine.eval("println(System.currentTimeMillis())");
engine.eval("println('Source: http://timyang.net/java/java-scriptingjava-scripting/')");
于是做了一个简单的socket服务器，把发过来的文本直接执行，然后再把脚本执行产生的内容返回给发送方。目标达成。共40余行代码(包括注释和花括号)，无需任何第三方library。代码如下：
// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");

while (true) {
    ServerSocket serverSocket = null;
    try {
        [...]]]></description>
			<content:encoded><![CDATA[<p>对于非Web的后台服务程序，经常会碰到这样的需求：</p>
<ol>
<li>动态改变程序运行时参数的能力。如Config.limitValue = 50</li>
<li>动态查看运行时候变量状态的能力，如 print(userMap.size())</li>
<li>执行代码的能力，如 userMap.clear()</li>
</ol>
<p>对于需求1,非Web的程序没法像PHP/JSP那样直接改就生效，往往改了某个值，即使是一个配置参数都需要服务器重启一下。这对于很多线上服务来说成本太高。</p>
<p>对于上述2的需求，通常是编写庞大的后台管理程序来满足。或者是通过增加日志输出，但问题是某些变量只需要偶尔才看一下，因此很多系统中大部分日志开销基本上是无用的。</p>
<p>对于需求3,只有通过在IDE的debug模式下才能达到。</p>
<p>我觉得所有的后台程序都应该具备这样的能力，为了满足以上需求，于是考虑在所有程序里面嵌入一个小型的解释脚本引擎来实现。就像很多游戏程序嵌入Lua/Python来动态执行代码目的一样。</p>
<p>今天先说下Java中的实现方法，几年前用过<a href="http://www.beanshell.org/" target="_blank">BeanShell</a>, 可以在Java VM里面解释执行多种类型脚本语言。但是发现已经多年不更新，原来是Java 6已经内建Scripting的支持，所以这些第三方的工具也都结束了历史使命。</p>
<p><span><span>Java 6自带的实际上是 <a href="http://www.mozilla.org/rhino">Mozilla Rhino</a> 的Java Script引擎，它使用JavaScript的语法，可以调用任意Java代码。</span></span>更多介绍见<a href="http://java.sun.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html" target="_blank">Java Scripting Programmer&#8217;s Guide</a>. <span><span>Rhino除了import写法有点特殊外，基本语法和Java代码基本一致。如：</span></span></p>
<pre>engine.eval("importClass(java.lang.System)");
engine.eval("println(System.currentTimeMillis())");
engine.eval("println('Source: <a href="http://timyang.net/java/java-scriptingjava-scripting/">http://timyang.net/java/java-scriptingjava-scripting/</a>')");</pre>
<p>于是做了一个简单的socket服务器，把发过来的文本直接执行，然后再把脚本执行产生的内容返回给发送方。目标达成。共40余行代码(包括注释和花括号)，无需任何第三方library。代码如下：</p>
<pre>// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");

while (true) {
    ServerSocket serverSocket = null;
    try {
        serverSocket = new ServerSocket(4444, 50, InetAddress.getByName("localhost"));
    } catch (IOException e) {
        System.err.println("Could not listen on port: 4444.");
        System.exit(1);
    }

    Socket clientSocket = null;
    try {
        clientSocket = serverSocket.accept();
    } catch (IOException e) {
        System.err.println("Accept failed.");
        System.exit(1);
    }

    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
            true);
    BufferedReader in = new BufferedReader(new InputStreamReader(
            clientSocket.getInputStream()));
    String inputLine, outputLine;

    while ((inputLine = in.readLine()) != null) {
        if ("quit".equals(inputLine))
                break;
        try {
            // evaluate JavaScript code from String
            out.println(engine.eval(inputLine));
        } catch (Exception e) {
            out.println("error:" + e.getMessage());
        }
    }
    out.close();
    in.close();
    clientSocket.close();
    serverSocket.close();
}</pre>
<p>启动程序之后只要 telnet localhost 4444 就可以执行任意代码并实时查看返回结果。</p>
<p>注意上面为了安全起见，只绑定了localhost地址，防止此功能被外部用户恶意使用。</p>
Similar Posts:<ul><li><a href="http://timyang.net/programming/c-erlang-java-performance/" rel="bookmark" title="November 11, 2009">C, Erlang, Java and Go Web Server performance test</a></li>

<li><a href="http://timyang.net/architecture/friendfeed-like-aggregator/" rel="bookmark" title="April 3, 2009">Ideas for creating a friendfeed like feed aggregator system</a></li>

<li><a href="http://timyang.net/linux/gearman-monitor/" rel="bookmark" title="August 26, 2009">利用Gearman来实现远程监控与管理</a></li>

<li><a href="http://timyang.net/lua/lua-coroutine-vs-java-wait-notify/" rel="bookmark" title="April 27, 2009">Lua coroutine vs Java wait/notify</a></li>

<li><a href="http://timyang.net/python/python-rest/" rel="bookmark" title="February 12, 2009">用Python实现CRUD功能REST服务</a></li>
</ul><!-- Similar Posts took 19.609 ms -->]]></content:encoded>
			<wfw:commentRss>http://timyang.net/java/java-scripting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java垃圾回收调优</title>
		<link>http://timyang.net/java/java_gc_tunning/</link>
		<comments>http://timyang.net/java/java_gc_tunning/#comments</comments>
		<pubDate>Wed, 07 Jan 2009 12:04:41 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[GC]]></category>

		<guid isPermaLink="false">http://timyang.net/?p=17</guid>
		<description><![CDATA[在Java中，通常通讯类型的服务器对GC(Garbage Collection)比较敏感。通常通讯服务器每秒需要处理大量进出的数据包，需要解析，分解成不同的业务逻辑对象并做相关的业务处理，这样会导致大量的临时对象被创建和回收。同时服务器如果需要同时保存用户状态的话，又会产生很多永久的对象，比如用户session。业务越复杂的应用往往用户session包含的引用对象就越多。这样在极端情况下会发生两件事情，long gc pause time 或 out of memory。
一，要解决long pause time首先要了解JVM中heap的结构

Java Heap为什么要分成几个不同的代(generation)? 由于80%-98%的对象的生存周期很短，大部分新对象存放在young generation可以很高效的回收，避免遍历所有对象。
young与old中内存分配的算法完全不同。young generation中由于存活的很少，要mark, sweep 然后再 compact 剩余的对象比较耗时，干脆把 live object copy 到另外一个空间更高效。old generation完全相反，里面的 live object 变化较少。因此采用 mark-sweep-compact更合适。

二，Java中四种垃圾回收算法
Java中有四种不同的回收算法，对应的启动参数为
–XX:+UseSerialGC
–XX:+UseParallelGC
–XX:+UseParallelOldGC
–XX:+UseConcMarkSweepGC
1. Serial Collector
大部分平台或者强制 java -client 默认会使用这种。
young generation算法 = serial
old generation算法 = serial (mark-sweep-compact)
这种方法的缺点很明显，stop-the-world, 速度慢。服务器应用不推荐使用。
2. Parallel Collector
在linux x64上默认是这种，其他平台要加 java -server 参数才会默认选用这种。
young = parallel，多个thread同时copy
old = mark-sweep-compact = 1
优点：新生代回收更快。因为系统大部分时间做的gc都是新生代的，这样提高了throughput(cpu用于非gc时间)
缺点：当运行在8G/16G server上old generation [...]]]></description>
			<content:encoded><![CDATA[<p>在Java中，通常通讯类型的服务器对GC(Garbage Collection)比较敏感。通常通讯服务器每秒需要处理大量进出的数据包，需要解析，分解成不同的业务逻辑对象并做相关的业务处理，这样会导致大量的临时对象被创建和回收。同时服务器如果需要同时保存用户状态的话，又会产生很多永久的对象，比如用户session。业务越复杂的应用往往用户session包含的引用对象就越多。这样在极端情况下会发生两件事情，long gc pause time 或 out of memory。</p>
<p>一，要解决long pause time首先要了解JVM中heap的结构</p>
<div id="attachment_18" class="wp-caption alignnone" style="width: 519px"><img class="size-full wp-image-18" title="java gc heap" src="http://timyang.net/blog/wp-content/uploads/2009/01/java-gc.png" alt="java gc heap" width="509" height="398" /><p class="wp-caption-text">java gc heap</p></div>
<ul>
<li>Java Heap为什么要分成几个不同的代(generation)? 由于80%-98%的对象的生存周期很短，大部分新对象存放在young generation可以很高效的回收，避免遍历所有对象。</li>
<li>young与old中内存分配的算法完全不同。young generation中由于存活的很少，要mark, sweep 然后再 compact 剩余的对象比较耗时，干脆把 live object copy 到另外一个空间更高效。old generation完全相反，里面的 live object 变化较少。因此采用 mark-sweep-compact更合适。</li>
</ul>
<p>二，Java中四种垃圾回收算法</p>
<p>Java中有四种不同的回收算法，对应的启动参数为<br />
–XX:+UseSerialGC<br />
–XX:+UseParallelGC<br />
–XX:+UseParallelOldGC<br />
–XX:+UseConcMarkSweepGC</p>
<p>1. Serial Collector<br />
大部分平台或者强制 java -client 默认会使用这种。<br />
young generation算法 = serial<br />
old generation算法 = serial (mark-sweep-compact)<br />
这种方法的缺点很明显，stop-the-world, 速度慢。服务器应用不推荐使用。</p>
<p>2. Parallel Collector<br />
在linux x64上默认是这种，其他平台要加 java -server 参数才会默认选用这种。<br />
young = parallel，多个thread同时copy<br />
old = mark-sweep-compact = 1<br />
优点：新生代回收更快。因为系统大部分时间做的gc都是新生代的，这样提高了throughput(cpu用于非gc时间)<br />
缺点：当运行在8G/16G server上old generation live object太多时候pause time过长</p>
<p>3. Parallel Compact Collector (ParallelOld)<br />
young = parallel = 2<br />
old = parallel，分成多个独立的单元，如果单元中live object少则回收，多则跳过<br />
优点：old old generation上性能较 parallel 方式有提高<br />
缺点：大部分server系统old generation内存占用会达到60%-80%, 没有那么多理想的单元live object很少方便迅速回收，同时compact方面开销比起parallel并没明显减少。</p>
<p>4. Concurent Mark-Sweep(CMS) Collector<br />
young generation = parallel collector = 2<br />
old = cms<br />
同时不做 compact 操作。<br />
优点：pause time会降低, pause敏感但CPU有空闲的场景需要建议使用策略4.<br />
缺点：cpu占用过多，cpu密集型服务器不适合。另外碎片太多，每个object的存储都要通过链表连续跳n个地方，空间浪费问题也会增大。</p>
<p>几条经验：<br />
1. java -server<br />
2. 设置Xms=Xmx=3/4物理内存<br />
3. 如果是CPU密集型服务器，使用–XX:+UseParallelOldGC, 否则–XX:+UseConcMarkSweepGC<br />
4. 新生代,Parallel/ParallelOld可设大于Xmx1/4，CMS可设小，小于Xmx1/4<br />
5. 优化程序，特别是每个用户的session中的集合类等。我们的一个模块中session中曾经为每个用户使用了一个ConcurrentHashMap, 里面通常只有几条记录，后来改成数组之后，每台机大概节约了1~2G内存。</p>
<p>不过总的说来，Java的GC算法感觉是业界最成熟的，目前很多其他语言或者框架也都支持GC了，但大多数都是只达到Java Serial gc这种层面，甚至分generation都未考虑。JDK7里面针对CMS又进行了一种改进，会采用一种G1(Garbage-First Garbage Collection)的算法。实际上<a href="http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf" target="_blank">Garbage-First paper</a>(PDF) 2004年已经出来了，相信到JDK7已经可以用于严格生产环境，有时间也会进一步介绍一下G1。<br />
另外在今年的Sun Tech Days上<a href="http://blogs.sun.com/joeys/" target="_blank">Joey Shen</a>讲的<a href="http://download.developers.sun.com.cn/event/sun_tech_day_china/2008/20081122_beijing_day2/track1/6_TD09_JavaPerformance_JoeyS.pdf" target="_blank">Improving Java Performance</a>(PDF)也是一个很好的Java GC调优的入门教程。</p>
Similar Posts:<ul><li><a href="http://timyang.net/programming/thrift-protocol-buffers-performance-java/" rel="bookmark" title="April 2, 2009">Thrift and Protocol Buffers performance in Java</a></li>

<li><a href="http://timyang.net/programming/thrift-protocol-buffers-performance-2/" rel="bookmark" title="April 17, 2009">Thrift and Protocol Buffers performance in Java Round 2</a></li>

<li><a href="http://timyang.net/programming/thrift-protocol-buffers-java-howto/" rel="bookmark" title="April 2, 2009">Thrift, Protocol Buffers installation and Java code howto</a></li>

<li><a href="http://timyang.net/lua/lua-coroutine-vs-java-wait-notify/" rel="bookmark" title="April 27, 2009">Lua coroutine vs Java wait/notify</a></li>

<li><a href="http://timyang.net/architecture/consistent-hashing-practice/" rel="bookmark" title="September 6, 2009">某分布式应用实践一致性哈希的一些问题</a></li>
</ul><!-- Similar Posts took 10.466 ms -->]]></content:encoded>
			<wfw:commentRss>http://timyang.net/java/java_gc_tunning/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
