日期:2014-05-16 浏览次数:20505 次
原文地址 :http://blog.csdn.net/gjyalpha/article/details/7163943
?
Oracle JDBC驱动程序可能会使用大量的内存。这是一种有意识的设计选择,在使用大量内存与提高性能之前做出权衡。在大多数情况下,对于大多数用户,这已被证明是一个不错的选择。一些用户已经经历了JDBC驱动程序使用的大量内存的问题。本白皮书正是写给这些用户。如果您的应用程序的性能表现是可接受的,那么你没有理由担心内存使用。如果您的应用程序并没有达到你所期望的性能,并且使用了比预期的更多的内存,那么请继续读下去。
7.3.4,8i和9i的Oracle JDBC驱动程序,使用差不多尽可能少的内存。不幸的是,这导致了不可接受的性能损失。在10g中,为了提高性能,驱动程序的体系结构被重新设计。在该体系结构重建的最重要的变化之一是驱动程序如何使用内存。开发团队做出了有针对性的决定,用内存换取性能。10g驱动程序因此比9i的驱动程序平均快约30%。当然,你所以测得的数据可能会有所不同。
由于内存价格相对比较便宜,伴随着10g驱动程序发布之后物理内存的大小也在显着地不断上涨,因此大多数用户都受益于(内存换性能的)性能改进。有一些用户,而且大部分是具有非常大规模应用的用户,已经看到了由于heap过大,垃圾收集器的trashing,甚至OutOfMemoryExceptions所引起的性能问题。在后续的版本中,开发团队一直在努力解决这些问题,通过改进驱动程序使用内存的方式,为用户提供额外的(内存使用)控制,以解决这些具体的问题。本白皮书介绍了驱动程序是如何使用内存的,应用程序特点如何具体地影响内存的使用,以及用户可以做些什么以更好地管理内存使用和提高应用程序性能。
注:在本文的其余部分的单词“驱动程序”本身是指10g及以后版本的Oracle JDBC驱动程序。其它情况会指明特定版本或被引用的版本。
10g的Oracle JDBC驱动程序,具有比以前的版本更大、更复杂的类层次结构。这些类的对象存储了更多的信息,所以需要更多的内存。这确实增加了内存的使用,但并这并不是真正的问题所在。真正的问题是用来存储查询结果的buffer。每个语句(包括PreparedStatement和CallableStatement的)都持有两个缓冲区,一个byte[](字节数组)和一个char [](字符数组)。char[]用来保存所有字符类型的行数据,如:CHAR,VARCHAR2,NCHAR等,byte[]用来保存所有的其它类型的行数据。这些buffer在在SQL被解析的时候分配,一般也就是在第一次执行该Statement的时候。Statement会持有这两个buffer,直到它被关闭。
由于buffer是在SQL解析的时候被分配的,buffer的大小并不取决于查询返回的行数据的实际长度,而是行数据可能的最大的长度。在SQL解析时,每列的类型是已知的,从该信息中驱动程序可以计算存储每一列所需的内存的最大长度。驱动程序也有fetchSize属性,也就是每次fetch返回的行数。有了每列有大小和行数的大小,驱动程序可以由此计算出一次fetch所返回的数据最大绝对长度。这也就是所分配的buffer的大小。
某些大类型,如LONG和LONG RAW,由于太大而无法直接存于buffer中会采取另外一种不同的处理方式。如果查询结果包含一个LONG或LONG RAW,将fetchSize设置为1之后,所遇见的内存问题就会变得明朗很多了。这种类型的问题不在这里讨论了。
字符数据存储在char[] buffer中。Java中的每个字符占用两个字节。一个VARCHAR2(10)列将包含最多10个字符,也就是10个Java的字符,也就是每行20个字节。一个VARCHAR2(4000)列将占用每行8K字节。重要的其实是column的定义大小,而不是实际数据的大小。一个VARCHAR2(4000)但是只包含了NULL的列,仍然需要每行8K字节。buffer是在驱动程序看到的查询结果之前被分配的,因此驱动程序必须分配足够的内存,以应付最大可能的行大小。一个定义为VARCHAR2(4000)的列最多可包含4000个字符。Buffer必须大到足以容纳4000个字符分配,尽管实际的结果数据可能没有那么大。
BFILE,BLOB和CLOB会被存储为locator。Locator可高达4K字节,每个BFILE,BLOB和CLOB列的byte[]必须有至少每行4K字节。RAW列最多可以包含4K字节。其它类型的则需要很少的字节。一个合理的近似值是假设所有其它类型的列,每行占用22个字节。