wenfengsun

Archive for March 2012

JNI:Java Native Interface,它允许Java代码和其他语言写的代码进行交互。
问题描述:
以JNI方式实现的jmagick在调用imagemagick的接口时,一直出现高内存消耗,最高达到10G内存。但是无论以jmx方式启动后,用jconsole监控Java Heap内存状况,还是用jmap-jhat方式dump并察看java Heap内存状况,都发现java Heap只占用了几百M内存。
这让人联想到了JNI的内存占用机制,首先,JVM内存结构如下图:

这个结构中,Nativeinterface组件:
与nativelibraries交互,是其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界,所以也很容易出现JVM无法控制的nativeheapOutOfMemory。
好,至此,我们大约知道了,JNI这种native方式产生的内存消耗是位于NativeMethodStack中,而不是Heap中,这也就解释了为何Heap内存消耗很小,而整个JVM占用内存很大的原因。
再次,来分析一下JNI编程时的实现方式:
Local Reference 和 Local Reference 表
理解 Local Reference 表的存在是理解 JNI Local Reference 的关键。
JNI Local Reference 的生命期是在 native method 的执行期(从 Java 程序切换到 native code 环境时开始创建,或者在 native method 执行时调用 JNI function 创建),在 native method 执行完毕切换回 Java 程序时,所有 JNI Local Reference 被删除,生命期结束(调用 JNI function 可以提前结束其生命期)。
实际上,每当线程从 Java 环境切换到 native code 上下文时(J2N),JVM 会分配一块内存,创建一个 Local Reference 表,这个表用来存放本次 native method 执行中创建的所有的 Local Reference。每当在 native code 中引用到一个 Java 对象时,JVM 就会在这个表中创建一个 Local Reference。比如,实例 1 中我们调用 NewStringUTF() 在 Java Heap 中创建一个 String 对象后,在 Local Reference 表中就会相应新增一个 Local Reference。

⑴运行 native method 的线程的堆栈记录着 Local Reference 表的内存位置(指针 p)。
⑵ Local Reference 表中存放 JNI Local Reference,实现 Local Reference 到 Java 对象的映射。
⑶ native method 代码间接访问 Java 对象(java obj1,java obj2)。通过指针 p 定位相应的 Local Reference 的位置,然后通过相应的 Local Reference 映射到 Java 对象。
⑷当 native method 引用一个 Java 对象时,会在 Local Reference 表中创建一个新 Local Reference。在 Local Reference 结构中写入内容,实现 Local Reference 到 Java 对象的映射。
⑸ native method 调用 DeleteLocalRef() 释放某个 JNI Local Reference 时,首先通过指针 p 定位相应的 Local Reference 在 Local Ref 表中的位置,然后从 Local Ref 表中删除该 Local Reference,也就取消了对相应 Java 对象的引用(Ref count 减 1)。
⑹当越来越多的 Local Reference 被创建,这些 Local Reference 会在 Local Ref 表中占据越来越多内存。当 Local Reference 太多以至于 Local Ref 表的空间被用光,JVM 会抛出异常,从而导致 JVM 的崩溃。
结论:
在每次调用JNI创建对象,并且执行完操作后,执行destroy方法释放回收native mem中的对象和内存,重新发布程序后,问题解决。

上周末到了杰科HD300 高清播放机+2T WD绿盘,准备一边当高清播放机,一边transmission下载。
可是令人恼火的是,杰科的linux系统并未开放ssh,ftp和telent端口,这让人一筹莫展。
后来经过摆弄菜单,发现在网络播放里,有一个BT选项,点进去就是transmission控制,可以设置简单的存储目的,速度限制等三个选项。但是通过上传PT种子下载,只能开始两个任务,这非常令人难以接受。
用windows在运行中访问网上邻居:\\192.168.x.x(你的高清机IP),可以进入内置硬盘中,我这里是D盘。
发现里面有transmission文件夹,进入,编辑settings.json,将rpc-whitelist修改为你所在的局域网,例如:192.168.1.*,*表示通配符。
此时,在浏览器输入:http://your_ip:9091,惊奇的发现进入了transmission的管理界面,这里可以开始多个任务。
至此OK,可以通过管理界面进行PT下载了。

首先,你需要一个vpn的帐号,来通过Ubuntu的vpn进行连接。连接就在网络菜单的vpn连接。
但是,通过vpn默认会将整个vpn配置为默认路由。这个可以在命令行模式下察看,点开term,在命令行输入route,会显示默认路由:
内核 IP 路由表
目标 网关 子网掩码 标志 跃点 引用 使用 接口
default 192.168.1.1 0.0.0.0 UG 0 0 0 wlan0
如果拨号vpn之后,默认路由变化了,则说明vpn抢走了你默认路由,这样所有的网络都会通过vpn访问,这不是我们的目的。
我们想那写墙了的网站,通过vpn访问,于是,我们先修改vpn不抢占默认路由。
选择路由,配置,选定对应的配置文件,点击编辑,弹出的窗口点击路由,弹出的新窗口,选中下方两个checkbox
1. 忽略自动获取的路由
2.仅将此连接用于相对应的网络上的资源
重新连接,发现vpn不再抢占默认路由,随后,我们想让google的访问走我们指定的vpn连接:
我们可以先ping一下google的ip地址:
># ping http://www.google.com.hk
PING www-hk.l.google.com (74.125.128.94) 56(84) bytes of data.
64 bytes from hg-in-f94.1e100.net (74.125.128.94): icmp_req=1 ttl=44 time=233 ms
看到这个ip地址是:74.125.128.94
通过设置路由来指定这个ip地址的访问通过vpn访问:
首先,vpn连接后,出现的新路由接口是ppp0
192.168.3.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0
可以在命令行先行测试:
输入:># route add -net 74.125.128.0 netmask 255.255.255.0 dev ppp0
再次执行route -n,可以看到新配置的路由已经生效:
74.125.128.0 0.0.0.0 255.255.255.0 U 0 0 0 ppp0
如果你的google已经被墙,这时再访问,惊奇的发现又可以访问了。
关于你的ip和子网掩码需要对应配置,例如ip:74.125.128.0,子网掩码最后一个段也需要是0,表示0-255范围。
现在我们可以通过ubuntu的配置界面配置这些路由。
打开网络菜单下的路由配置,选中你的路由配置,点编辑选项,弹出窗口中选择路由,
将74.125.128.0填入第一个字段,255.255.255.0填入第二个,然后勾选最下方的两个checkbox,保存。
重新连接vpn,这时你通过route -n可以发现新配置的路由已经生效了。
好,基本方法有了,如果你需要访问twitter,你需要首先收集twitter的所有host信息,加入/etc/hosts,然后将配置的host中的所有网段都加入到vpn的路由策略中,重新连接路由,就可以访问twitter.com了。

1. 安装PCRE(Perl Compatible Regular Expressions)
地址:http://sourceforge.net/projects/pcre/files/pcre/8.30/pcre-8.30.tar.gz/download
执行:./configure make&make install
此模块用于正则表达式,nginx rewrite
2. 安装zlib(用于gzip模块)
地址:http://www.linuxidc.com/upload/2008_09/08091520581351.tar
执行:./configure make&make install
3. 安装nginx(1.0.13)
地址:http://nginx.org/download/nginx-1.0.13.tar.gz
./configure make&make install
4. 启动nginx,可能会报错:
[root@sever sbin]# ./nginx
./nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
切换到/usr目录,执行:ln -s /usr/local/lib/libpcre.so.1 /lib
在/lib中添加一个软链接。
再次启动,OK。