Chris's Blog

Keep Walking......

Spring NamedParameterJdbcTemplate的内存泄漏问题

我们的项目是使用Spring JDBC来操作DB的,通常是直接使用SimpleJdbcTemplate,一直以来也没发现什么问题。今天在做performance test的时候,发现内存增长很快,甚至出现了out of memory。把heap dump拉下来查看后,发现是这次新加的一个service出现了问题,但根源是因为NamedParameterJdbcTemplate中的HashMap导致的。

这里要先说明使用的Spring的版本是2.5.6,在3.0.3中已修复该问题。

垃圾收集器及内存分配

程序计数器、虚拟机栈和本地方法栈的内存分配大体在编译器就可以确定,并且这些区域和线程有着相同的生命周期,在方法或线程结束时,内存也就回收了。而Java堆和方法区的内存分配和回收都是动态的,只有在程序运行期间才知道会创建哪些对象,因此是垃圾收集器所关注的内存区域。

对象标记算法

Java堆中存放着所有对象实例,垃圾收集器在进行回收前,需要根据算法来确定哪些对象已不再被使用,可进行回收。

引用计数算法

该算法是给对象添加一个引用计数器,每当有引用它时,计数器就加1;当引用失效时,计数器就减1;当计数器为0时就不能被使用了。这种算法的判定效率很高,但是很难解决Java对象之间的循环引用问题,因此未被Java语言采用。

根搜索算法

通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象当GC Roots没有任何引用链相连时,则此对象就不能被使用了。

可作为GC Roots的对象包括: - 虚拟机栈中的局部变量表所引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中JNI所引用的对象。

Korn Shell Script

基本语法

”;”作为语句的结束,因此可以将多个command写在一行。

 print -n "Name: "; read name; print ""

“\” 可将第二行command与第一行连接起来,若command太长,可通过这种方式写在多行上。

 grep filename | sort -u | awk '{print $4}' | \
 uniq -c >> /longpath/file

Variables

Arrays

arrname[1]=4 To fill in
print ${arraname[1]} To print out
${arrname[*]} Get all elements
${#arrname[*]} Get the number of elements

The Foundation of Spring Batch

Spring Batch是埃森哲贡献给Spring的一个开源项目,现在由双方共同维护。通过Spring Batch可以构建出轻量级的大数据量并⾏处理应⽤,⽀持事务、并发、流程、监控、纵向和横向扩展,提供统一的接口管理。Spring Batch并不包含scheduler,它只是一个通用的batch处理框架,你可以通过QuartZ,Control-M等scheduler去调用。

Spring Batch能够处理大批量数据的导入、导出和业务逻辑计算,执行过程无需人工干预。我们的系统是一个金融产品信息的数据中心,需要从不同的系统读取产品信息,也需要将这些信息提供给其它的系统,这种data loading就是Spring Batch的一种应用场景。

Common Format of CSV Files

CSV是一种常见的文件格式,常用于不同系统之间的数据交换,对于该文件格式可以简单描述为:一组使用逗号“,”分隔字段,并以换行符作为一行数据结束的数据集合。该文件可以使用Microsoft Excel查看,但是中文字符会显示为乱码。

这个描述就真的只是简单描述,实际上CSV的格式处理没有这么简单。最近在和另外一个系统做集成,我们的系统会提供CSV数据文件给对方系统处理,由于我们系统中个别字段会包括换行符“CRLF”(这是遗留系统,就不用纠结为什么字段中会包含换行符了),也就是说一个字段可能会显示在几行上,但是这个字段是包含在双引号中的,结果对方系统就处理不了了。因为对方系统只是简单的按行处理数据,用逗号解析字段。

JVM运行时内存区域

Java虚拟机管理的运行时数据区域:

  • 程序计数器

    是当前线程所执行的字节码的行号指示器。每条线程都有一个独立的程序计数器,各线程之间的计数器互不影响,该内存区域为线程私有,也不会出现OutOfMemoryError。

  • Java虚拟机栈

    该区域也是线程私有,其生命周期与线程相同。虚拟机栈表述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

Supplementary Characters in Java

工作中经常会涉及到文件处理,而fixlength类型的文件又是一种很常见的格式。众所周知,fixlength类型的数据就是每个字段对应一行数据中固定长度的字符,每个字段都有对应的start offset和end offset,用实现来表示就是String.substring(start, end),所以start和end的位置是至关重要的,一个字段对应错了,后面的字段就全错了。

在Java中使用UTF-16来表示unicode字符,一个字符就是16 bit,像String.length()就是返回有多少个16 bit。unicode支持的字符的code point范围是U+0000到U+10FFFF,这其中包括基本字符(BMP)和补充字符(supplementary character),基本字符时从U+0000到U+FFFF,补充字符从U+10000到U+10FFFF。

The Syntax of Markdown

Octopress使用的是markdown语法,和wiki的语法有点相似,但又不完全相同,这里将常用的语法记录下来便于查阅。

标题

标题用#开头,一个#是一级标题,两个#是二级标题,#越多字体越小。

Octopress常用命令

Octopress经常使用到的命令,在这里做个总结,方面查阅。

rake new_post["title"]

创建一个post。

rake new_page[super-awesome/page.html]

创建一个page。

New Blog Opening

新blog开张啦,以此博文作为纪念。

这些年折腾了好几个博客了,但加起来的文字总共也没有多少,我的热乎劲也就在搭建那一刹那,特别是像在GAE上要自己去折腾整个过程。所以说,我并不热衷于写博客,而是中意于搭建这样一个小站的过程。说到原因呢,可能是因为哥曾经也是个web developer,但最近几年一直在做backend,把以前的frontend功底也丢的差不多了,所以每次遇到这样的机会,总是会让我心潮澎湃。