??xml version="1.0" encoding="utf-8" standalone="yes"?> Qibm:developerworks中国|站 Ƨ阳辰周? 一 问题的提?/a> Java的一个重要优点就是通过垃圾攉?Garbage CollectionQGC)自动理内存的回ӞE序员不需要通过调用函数来释攑ֆ存。因此,很多E序员认为Java不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的责QQ而是GC或JVM的问题。其实,q种x是不正确的,因ؓJava也存在内存泄Ԍ但它的表CC++不同? 随着来多的服务器E序采用Java技术,例如JSPQServletQ?EJB{,服务器程序往往长期q行。另外,在很多嵌入式pȝ中,内存的总量非常有限。内存泄露问题也变得十分关键,即每次q行量泄漏Q长期运行之后,pȝ也是面崩溃的危险? ?Java是如何管理内?/a> Z判断Java中是否有内存泄露Q我们首先必M解Java是如何管理内存的。Java的内存管理就是对象的分配和释N题。在Java中,E序员需要通过关键字new为每个对象申请内存空?(基本cd除外)Q所有的对象都在?(Heap)中分配空间。另外,对象的释放是由GC军_和执行的。在Java中,内存的分配是q序完成的Q而内存的释放是有GC完成的,q种收支两条U的Ҏ实化了E序员的工作。但同时Q它也加重了JVM的工作。这也是JavaE序q行速度较慢的原因之一。因为,GCZ能够正确释放对象QGC必须监控每一个对象的q行状态,包括对象的申诗引用、被引用、赋值等QGC都需要进行监控? 监视对象状态是Z更加准确地、及时地释放对象Q而释攑֯象的Ҏ原则是该对象不再被引用? Z更好理解GC的工作原理,我们可以对象考虑为有向图的顶点,引用关p考虑为图的有向边Q有向边从引用者指向被引对象。另外,每个U程对象可以作ؓ一个图的v始顶点,例如大多E序从mainq程开始执行,那么该图是以mainq程点开始的一|树。在q个有向图中Q根点可达的对象都是有效对象,GC不回收q些对象。如果某个对?(q通子?与这个根点不可?注意Q该图ؓ有向?Q那么我们认?q些)对象不再被引用,可以被GC回收? 以下Q我们D一个例子说明如何用有向图表C内存管理。对于程序的每一个时刻,我们都有一个有向图表示JVM的内存分配情c以下右图,是左边E序q行到第6行的C意图? Java使用有向囄方式q行内存理Q可以消除引用@环的问题Q例如有三个对象Q相互引用,只要它们和根q程不可辄Q那么GC也是可以回收它们的。这U方式的优点是管理内存的_ֺ很高Q但是效率较低。另外一U常用的内存理技术是使用计数器,例如COM模型采用计数器方式管理构Ӟ它与有向囄比,_ֺ行低(很难处理循环引用的问?Q但执行效率很高? 下面Q我们就可以描述什么是内存泄漏。在Java中,内存泄漏是存在一些被分配的对象,q些对象有下面两个特点,首先Q这些对象是可达的,卛_有向图中Q存在通\可以与其相连Q其ơ,q些对象是无用的Q即E序以后不会再用这些对象。如果对象满两个条gQ这些对象就可以判定为Java中的内存泄漏Q这些对象不会被GC所回收Q然而它却占用内存? 在C++中,内存泄漏的范围更大一些。有些对象被分配了内存空_然后却不可达Q由于C++中没有GCQ这些内存将永远收不回来。在Java中,q些不可辄对象都由GC负责回收Q因此程序员不需要考虑q部分的内存泄露? 通过分析Q我们得知,对于C++Q程序员需要自q理边和顶点,而对于JavaE序员只需要管理边可以了(不需要管理顶点的释放)。通过q种方式QJava提高了编E的效率? 因此Q通过以上分析Q我们知道在Java中也有内存泄漏,但范围比C++要小一些。因为Java从语a上保证,M对象都是可达的,所有的不可辑֯象都由GC理? 对于E序员来_GC基本是透明的,不可见的。虽Ӟ我们只有几个函数可以讉KGCQ例如运行GC的函数System.gc()Q但是根据Java语言规范定义Q?该函C保证JVM的垃圾收集器一定会执行。因为,不同的JVM实现者可能用不同的法理GC。通常QGC的线E的优先U别较低。JVM调用GC的策略也有很多种Q有的是内存使用到达一定程度时QGC才开始工作,也有定时执行的,有的是^~执行GCQ有的是中断式执行GC。但通常来说Q我们不需要关心这些。除非在一些特定的场合QGC的执行媄响应用程序的性能Q例如对于基于Web的实时系l,如网l游戏等Q用户不希望GCH然中断应用E序执行而进行垃圑֛Ӟ那么我们需要调整GC的参敎ͼ让GC能够通过q缓的方式释攑ֆ存,例如垃圑֛收分解ؓ一pd的小步骤执行QSun提供的HotSpot JVM支持这一Ҏ? 下面l出了一个简单的内存泄露的例子。在q个例子中,我们循环甌Object对象Qƈ所甌的对象放入一个Vector中,如果我们仅仅释放引用本nQ那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,q必MVector中删除,最单的Ҏ是Vector对象讄为null? Vector v=new Vector(10); ?如何内存泄?/a> 最后一个重要的问题Q就是如何检Java的内存泄漏。目前,我们通常使用一些工h查JavaE序的内存泄漏问题。市Z已有几种专业查Java内存泄漏的工P它们的基本工作原理大同小异,都是通过监测JavaE序q行Ӟ所有对象的甌、释攄动作Q将内存理的所有信息进行统计、分析、可视化。开发h员将Ҏq些信息判断E序是否有内存泄漏问题。这些工具包括Optimizeit ProfilerQJProbe ProfilerQJinSight , Rational 公司的Purify{? 下面Q我们将单介lOptimizeit的基本功能和工作原理? Optimizeit Profiler版本4.11支持ApplicationQAppletQServlet和Romote Application四类应用Qƈ且可以支持大多数cd的JVMQ包括SUN JDKpdQIBM的JDKpdQ和Jbuilder的JVM{。ƈ且,该Y件是由Java~写Q因此它支持多种操作pȝ。Optimizeitpdq包括Thread Debugger和Code Coverage两个工具Q分别用于监运行时的线E状态和代码覆盖面? 当设|好所有的参数了,我们可以在OptimizeIt环境下运行被程序,在程序运行过E中QOptimizeit可以监视内存的用曲U?如下?Q包括JVM甌的堆(heap)的大,和实际用的内存大小。另外,在运行过E中Q我们可以随时暂停程序的q行Q甚臛_行调用GCQ让GCq行内存回收。通过内存使用曲线Q我们可以整体了解程序用内存的情况。这U监对于长期运行的应用E序非常有必要,也很Ҏ发现内存泄露? 在运行过E中Q我们还可以从不同视角观查内存的使用情况QOptimizeit提供了四U方式: 在运行过E中Q我们可以随时观察内存的使用情况Q通过q种方式Q我们可以很快找到那些长期不被释放,q且不再使用的对象。我们通过查这些对象的生存周期Q确认其是否为内存泄霌Ӏ在实践当中Q寻扑ֆ存泄露是一仉帔R烦的事情Q它需要程序员Ҏ个程序的代码比较清楚Qƈ且需要丰富的调试l验Q但是这个过E对于很多关键的JavaE序都是十分重要的? lg所qͼJava也存在内存泄露问题,其原因主要是一些对象虽然不再被使用Q但它们仍然被引用。ؓ了解册些问题,我们可以通过软g工具来检查内存泄Ԍ查的主要原理是暴露出所有堆中的对象Q让E序员寻N些无用但仍被引用的对象? 文章: 软gQ?br>Sitraka Software's Jprobe http://www.sitraka.com 关于作?/a> 在通常情况下,一?U程 不能讉K另外一?U程 的堆栈变量,而且q个 U程 必须处于如下状态之一Q?nbsp; 1.排队状态(readyQ,在用户创Z一?U程 以后Q这?U程 不会立即q行。当 U程 中的Ҏstart()被调用时Q这?U程 ׃q行排队状态,{待调度E序它转入q行状态(runningQ。当一个进E被执行后它也可以进行排队状态。如果调度程序允许的话,通过调用Ҏyield()可以将q程攑օ排队状态?nbsp; 2.q行状?running)Q当调度E序cpu的运行时间分配给一?U程 Q这?U程 p入了q行状态开始运行?nbsp; 3.{待状态(waitingQ,很多原因都可以导?U程 处于{待状态,例如 U程 执行q程中被暂停Q或者是{待i/oh的完成而进入等待状态?nbsp; ?java 中不同的 U程 h不同的优先Q高优先U的 U程 可以安排在低优先U?U程 之前完成。如果多?U程 h相同的优先Q?java 会在不同?U程 之间切换q行。一个应用程序可以通过使用 U程 中的Ҏsetpriority()来设|?U程 的优先Q用方法getpriority()来获得一?U程 的优先?nbsp; U程 的生命周? 一?U程 的的生命周期可以分成两阶D:生存QaliveQ周期和MQdeadQ周期,其中生存周期又包括运行状态(runningQ和{待状态(waitingQ。当创徏一个新 U程 后,q个 U程 p入了排队状态(readyQ,?U程 中的Ҏstart()被调用时Q?U程 p入生存周期,q时它的Ҏisalive()始终q回真|直至 U程 q入M状态?nbsp; U程 的实? 有两U方法可以实?U程 Q一U是扩展 java .lang.threadc,另一U是通过 java .lang.runnable接口?nbsp; 一、堆?stack)和堆(heap)Q? Q1Q内存分配的{略 按照~译原理的观?E序q行时的内存分配有三U策?分别是静态的,栈式?和堆式的. 静态存储分配是指在~译时就能确定每个数据目标在q行时刻的存储空间需?因而在~译时就可以l他们分配固定的内存I间.q种分配{略要求E序代码中不允许有可变数据结?比如可变数组)的存?也不允许有嵌套或者递归的结构出?因ؓ它们都会D~译E序无法计算准确的存储空间需? 栈式存储分配也可UCؓ动态存储分?是由一个类g堆栈的运行栈来实现的.和静态存储分配相?在栈式存储方案中,E序Ҏ据区的需求在~译时是完全未知?只有到运行的时候才能够知道,但是规定在运行中q入一个程序模块时,必须知道该程序模块所需的数据区大小才能够ؓ其分配内?和我们在数据l构所熟知的栈一?栈式存储分配按照先进后出的原则进行分配? 静态存储分配要求在~译时能知道所有变量的存储要求,栈式存储分配要求在过E的入口处必ȝ道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或I闲块组?堆中的内存可以按照Q意顺序分配和释放. Q2Q堆和栈的比? 上面的定义从~译原理的教材中ȝ而来,除静态存储分配之?都显得很呆板和难以理?下面撇开静态存储分?集中比较堆和? 从堆和栈的功能和作用来通俗的比? 堆主要用来存攑֯象的Q栈主要是用来执行程序的 .而这U不同又主要是由于堆和栈的特点决定的: 在编E中Q例如C/C++中,所有的Ҏ调用都是通过栈来q行?所有的局部变?形式参数都是从栈中分配内存空间的。实际上也不是什么分?只是从栈向上用p,好像工厂中的传送带(conveyor belt)一?Stack Pointer会自动指引你到放东西的位|?你所要做的只是把东西放下来就?退出函数的时候,修改栈指针就可以把栈中的内容销?q样的模式速度最?当然要用来运行程序了.需要注意的?在分配的时?比如Z个即要调用的程序模块分配数据区?应事先知道这个数据区的大?也就说是虽然分配是在E序q行时进行的,但是分配的大多是定?不变?而这?大小多少"是在~译时确定的,不是在运行时. 堆是应用E序在运行的时候请求操作系l分配给自己内存Q由于从操作pȝ理的内存分?所以在分配和销毁时都要占用旉Q因此用堆的效率非常?但是堆的优点在于,~译器不必知道要从堆里分配多存储空_也不必知道存储的数据要在堆里停留多长的时?因此,用堆保存数据时会得到更大的灵zL。事实上,面向对象的多态?堆内存分配是必不可少?因ؓ多态变量所需的存储空间只有在q行时创Z对象之后才能定.在C++中,要求创徏一个对象时Q只需用new命o~制相关的代码即可。执行这些代码时Q会在堆里自动进行数据的保存.当然Qؓ辑ֈq种灉|性,必然会付Z定的代h:在堆里分配存储空间时会花掉更长的旉Q这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的?人的优点往往也是人的~点,人的~点往往也是人的优点(晕~). Q3QJVM中的堆和? JVM是基于堆栈的虚拟?JVM为每个新创徏的线E都分配一个堆?也就是说,对于一个JavaE序来说Q它的运行就是通过对堆栈的操作来完成的。堆栈以帧ؓ单位保存U程的状态。JVM对堆栈只q行两种操作:以为单位的压栈和出栈操作? 我们知道,某个U程正在执行的方法称为此U程的当前方?我们可能不知?当前Ҏ使用的UCؓ当前帧。当U程ȀzM个JavaҎ,JVM׃在线E的Java堆栈里新压入一个。这个自然成ؓ了当前.在此Ҏ执行期间,q个帧将用来保存参数,局部变?中间计算q程和其他数?q个帧在q里和编译原理中的活动纪录的概念是差不多? 从Java的这U分配机制来?堆栈又可以这L?堆栈(Stack)是操作系l在建立某个q程时或者线E?在支持多U程的操作系l中是线E?个线E徏立的存储区域Q该区域h先进后出的特性? 每一个Java应用都唯一对应一个JVM实例Q每一个实例唯一对应一个堆。应用程序在q行中所创徏的所有类实例或数l都攑֜q个堆中,q由应用所有的U程׃n.跟C/C++不同QJava中分配堆内存是自动初始化的。Java中所有对象的存储I间都是在堆中分配的Q但是这个对象的引用却是在堆栈中分配,也就是说在徏立一个对象时从两个地斚w分配内存Q在堆中分配的内存实际徏立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指?引用)而已?/p> 一、堆?stack)和堆(heap)Q? Q1Q内存分配的{略 按照~译原理的观?E序q行时的内存分配有三U策?分别是静态的,栈式?和堆式的. 静态存储分配是指在~译时就能确定每个数据目标在q行时刻的存储空间需?因而在~译时就可以l他们分配固定的内存I间.q种分配{略要求E序代码中不允许有可变数据结?比如可变数组)的存?也不允许有嵌套或者递归的结构出?因ؓ它们都会D~译E序无法计算准确的存储空间需? 栈式存储分配也可UCؓ动态存储分?是由一个类g堆栈的运行栈来实现的.和静态存储分配相?在栈式存储方案中,E序Ҏ据区的需求在~译时是完全未知?只有到运行的时候才能够知道,但是规定在运行中q入一个程序模块时,必须知道该程序模块所需的数据区大小才能够ؓ其分配内?和我们在数据l构所熟知的栈一?栈式存储分配按照先进后出的原则进行分配? 静态存储分配要求在~译时能知道所有变量的存储要求,栈式存储分配要求在过E的入口处必ȝ道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或I闲块组?堆中的内存可以按照Q意顺序分配和释放. Q2Q堆和栈的比? 上面的定义从~译原理的教材中ȝ而来,除静态存储分配之?都显得很呆板和难以理?下面撇开静态存储分?集中比较堆和? 从堆和栈的功能和作用来通俗的比? 堆主要用来存攑֯象的Q栈主要是用来执行程序的 .而这U不同又主要是由于堆和栈的特点决定的: 在编E中Q例如C/C++中,所有的Ҏ调用都是通过栈来q行?所有的局部变?形式参数都是从栈中分配内存空间的。实际上也不是什么分?只是从栈向上用p,好像工厂中的传送带(conveyor belt)一?Stack Pointer会自动指引你到放东西的位|?你所要做的只是把东西放下来就?退出函数的时候,修改栈指针就可以把栈中的内容销?q样的模式速度最?当然要用来运行程序了.需要注意的?在分配的时?比如Z个即要调用的程序模块分配数据区?应事先知道这个数据区的大?也就说是虽然分配是在E序q行时进行的,但是分配的大多是定?不变?而这?大小多少"是在~译时确定的,不是在运行时. 堆是应用E序在运行的时候请求操作系l分配给自己内存Q由于从操作pȝ理的内存分?所以在分配和销毁时都要占用旉Q因此用堆的效率非常?但是堆的优点在于,~译器不必知道要从堆里分配多存储空_也不必知道存储的数据要在堆里停留多长的时?因此,用堆保存数据时会得到更大的灵zL。事实上,面向对象的多态?堆内存分配是必不可少?因ؓ多态变量所需的存储空间只有在q行时创Z对象之后才能定.在C++中,要求创徏一个对象时Q只需用new命o~制相关的代码即可。执行这些代码时Q会在堆里自动进行数据的保存.当然Qؓ辑ֈq种灉|性,必然会付Z定的代h:在堆里分配存储空间时会花掉更长的旉Q这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的?人的优点往往也是人的~点,人的~点往往也是人的优点(晕~). Q3QJVM中的堆和? JVM是基于堆栈的虚拟?JVM为每个新创徏的线E都分配一个堆?也就是说,对于一个JavaE序来说Q它的运行就是通过对堆栈的操作来完成的。堆栈以帧ؓ单位保存U程的状态。JVM对堆栈只q行两种操作:以为单位的压栈和出栈操作? 我们知道,某个U程正在执行的方法称为此U程的当前方?我们可能不知?当前Ҏ使用的UCؓ当前帧。当U程ȀzM个JavaҎ,JVM׃在线E的Java堆栈里新压入一个。这个自然成ؓ了当前.在此Ҏ执行期间,q个帧将用来保存参数,局部变?中间计算q程和其他数?q个帧在q里和编译原理中的活动纪录的概念是差不多? 从Java的这U分配机制来?堆栈又可以这L?堆栈(Stack)是操作系l在建立某个q程时或者线E?在支持多U程的操作系l中是线E?个线E徏立的存储区域Q该区域h先进后出的特性? 每一个Java应用都唯一对应一个JVM实例Q每一个实例唯一对应一个堆。应用程序在q行中所创徏的所有类实例或数l都攑֜q个堆中,q由应用所有的U程׃n.跟C/C++不同QJava中分配堆内存是自动初始化的。Java中所有对象的存储I间都是在堆中分配的Q但是这个对象的引用却是在堆栈中分配,也就是说在徏立一个对象时从两个地斚w分配内存Q在堆中分配的内存实际徏立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指?引用)而已?/p>
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}
//此时Q所有的Object对象都没有被释放Q因为变量v引用q些对象?
Jim Patrick, Handling memory leaks in Java programs,
http://www-106.ibm.com/developerWorks/library/j-leaks/index.html
Ed Lycklama, Does Java Technology Have Memory Leaks?
http://www.klgroup.com/javaone
Sun, The Java HotSpot Virtual Machine, Technical White Paper
Boland Software's Optimizeit http://optimizeit
IBM alphaWorks' Jinsight http://www.alphaworks.ibm.com/tech/jinsight
Ƨ阳辎ͼ北京大学计算机硕士毕业,98qv开始研I基于java的Y件开发、测试,参与开发、测试过多个ZJava的应用程序和Web服务目。联pL?a href="mailto:yeekee@sina.com">yeekee@sina.com
周欣Q北京大学计机pdd士生Q主要研I方向:E序理解、逆向工程及Y件度量,联系方式 zhouxin@sei.pku.edu.cn
* 一个组成部分是操作pȝ用来理q程的内核对象。内核对象也是系l用来存攑օ于进E的l计信息的地斏V?nbsp;
* 另一个组成部分是地址I间Q它包含所有可执行模块或DLL模块的代码和数据。它q包含动态内存分配的I间。如U程堆栈和堆栈分配空间?nbsp;
q程是不zL的。若要ɘq程完成某项操作Q它必须拥有一个在它的环境中运行的U程Q该U程负责执行包含在进E的地址I间中的代码。实际上Q单个进E可能包含若q个U程Q所有这些线E都“同时”执行进E地址I间中的代码。ؓ此,每个U程都有它自q一lCPU寄存器和它自q堆栈。每个进E至拥有一个线E,来执行进E的地址I间中的代码。如果没有线E来执行q程的地址I间中的代码Q那么进E就没有存在的理׃Q系l就自动撤消该q程和它的地址I间?nbsp;
若要使所有这些线E都能运行,操作pȝp为每个线E安排一定的CPU旉。它通过以一U@环方式ؓU程提供旉片(UCؓ量程Q,从而造成一U假象,仿佛所有线E都是同时运行的一栗?nbsp;
当创Z个进E时Q系l会自动创徏它的W一个线E,UCؓȝE。然后,该线E可以创建其他的U程Q而这些线E又能创建更多的U程?nbsp;
---------------------------------------------------------------摘自 《Windows 核心~程?
q程有三大部?代码Dc数据段、PCBQ进E控制段Q?br>操作pȝ正是通过PCB来管理这多个q程。在q样的系l里Q进E是操作pȝ独立调度和分z基本单位Q又是一个可拥有资源的独立单位?br>U程Q系l调度和分派的基本单位?br>q程和线E有如下不同Q?br> q程可以拥有资源Q线E共享进E拥有的资源
q程间的切换必须保存PCB
---------------------------------------------------------------
微Y官方对进E和U程的定?
q程Q用最z的话来_q程是一个正在执行的E序Q一个或多个U程在进E中q行Q线E是操作pȝ分配CPUq算旉的最单位。每一个进E都提供了运行一个程序所必需的资源,一个进E具?GB的虚拟地址I间QWindows NT Server Enterprise Edition及Windows 2000 Advanced Server中低3GB虚拟地址I间供进E用,?GB供操作系l的内核代码使用。Windows NT/2000中低2GB供进E用,?GB供操作系l内总码用。Windows9XQ?—?4K只读I间用来装入Microsoft DOS信息Q?4K—?M装入DOS的兼容代码,4M—?GB的私有空间供q程使用Q?GB—?GB的共享空间装入各UDLL代码Q?GB—?GB为共享的pȝ内核代码I间Q其中共享的2GB—?GB的空间是99%的“内存无效页错误”、“General Protect Error(GPE)”及蓝屏的罪祸首。)Q可执行代码Q数据,对象句柄Q环境变量,优先权以及设|最大化最化的功能。每一个进E都从一个主U程开始执行,但可以在它所拥有的线E中创徏额外的线E。一个进E的所有线E共享进E的虚拟地址I间和系l资源,一个线E的资源包括U程的机器寄存器讄Q内核堆栈,U程环境变量和进E虚拟地址中的用户堆栈?br>---------------------------------------------------------------
两者的区别。根据定义,q程Z个数据结构及能在其上q行的一ơ操作,它有两个基本特征Q一个是q程是可用有资源的独立单位,W二个是q程同时又是一个可以独立调度和分派的基本单位,q两个基本属性之能够独立运行,也能够ƈ发运行。但是在q发q行的时候,pȝq需要执行一pd操作Q?br> 1、需要创E,qؓ之分配其所必需的资源?br> 2、撤销q程Q对资源q行回收?br> 3、进E切换,它需要保留当前进E的CPU环境和设|新选中q程的CPU环境Qؓ此需要花费不处理时间。正因ؓq程拥有资源Q所以在q发执行q程的时候,在创建、撤销和切换种Q系l需要付大的开销Q因此,pȝ中设|的q程不能太多Q进E切换的频率也不能过高,q就限制了ƈ发程度的提高。ؓ了解册一问题Q于是生ƈ引入了线E概c?nbsp;
U程是进E中的一个实体,它的基本思想是将E序的执行和资源分开Q只拥有一点必不可的资源。一个进E可用有多个U程Q但它可以和同属于同一q程的其他线E共享进E所拥有的所有的资源Q同一q程中的U程之间可以q发执行。这L话,q发E度可以获得显著的提高。线E也h许多q程所h的特征,因此被称型进E?br>---------------------------------------------------------------|上攉
|上Ҏ很多,据说有两U方法可以连接远E数据库,一U是使用服务理里Oracle Net Manager的的囑Ş界面操作,q种我尝试了一?没有成功.. 于是 我尝试第二种. W二U方法是 直接修改Oracle数据库的文g.我觉得这Ҏ比较?于是在这里记一?
操作步骤:
1)
打开目录D:\oracle安装目录\ora92\network\admin中的文gtnsnames.ora?
2) d代码:
WAREHOUSE =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST=10.1.10.158)(PORT = 1521))
)
(CONNECT_DATA =
(SID = orcl )
)
)
修改说明:
WAREHOUSE:q名字是你用来连接的名字,随便?
10.1.10.158:q程计算机的IP地址.
orcl : q程计算机数据库?
保存之后可以了.
PS:在admin 文g夹中q看到其他的名字,感觉q名字很熟悉,找个旉也看看这些个文g间的兌.应该是一件有意思的事情
转自 http://www.blogcn.com/user69/galiasun/index.html
本来想l谈JDBC的高U连l方?事务模式.但发现关于大对象存储有很多h在问,所?br>先来插入一节关于大对象存储的内?然后再接着原来的思\写下?
JDBC的大对象存储听v来复?其实如果你明白了原理以后,非常简?|上有关q方面的
教材很少,而SUN的文档中,我从1.2开始看C在仍然是错误?不知道写文档的h长脑子没
?那几行代码你试试不q道了,q么多次重抄下来q是错误?
大对象分c?一般来?大对象分?大的文本对象,比如一个很长的文本(请你要注意什么是
文本文g,什么是二进制文?文g,或者是你定义的一个长字符?比如你定义了:
String s = "我们要去吃饭?.....................然后睡觉!";
从吃饭到睡觉中间省略了实际的10000000000000?虽然你不会真的定义这么称的String,?br>有时会从什么地方得到这LString,要写到数据库?
另一U就是大的二q制对象,象执行文?图象文g{?注意,word,excel,pptq些"带格?的文
档都应该以二q制对象存储.
一般来?数据库如果支持大对象存储,会有q几U类型的SQL数据cd:
BLOB,CLOCB,NLOB,也有的数据数只有一UBLOB,基本上是q样?BLOB用来存放二进制文??br>CLOB用来存放文本文g,NLOB是对多字节文本文件支?假如你的文本文g是纯英文?攑֜
BLOB中当然可?也就是说它是以byte格式存储?而多字节是以CHAR格式存储?
同样对于q几U类型的文档,有几U相对应的存取方?
setter:
利用PreparedStatement的setXXXҎ,
setAsciiStream()Ҏ用于写入一般的文本?setBinaryStream()Ҏ用于写入二进制流
而setUnicodeStream()用于写好UNICODE~码的文?与此相对应的ResultSet中三个getterҎ
用于取回:getAsciiStream(),getBinaryStream(),getBinaryStream().
对于文g本n,要把它作Z个流,只要new InputStream(new FileInputStream("文g路径")
可以了,但对于大的String对象,你不会写入文件再转换成输入流?
new StringBufferInputStream(String s),C?
JDBC2以后提供了java.sql.BLOB对象,我不大家使用?一是很ȝ,二是Ҏ出错,要先?br>入一个空的BLOB对象,然后再填充它,实在没有必要,直接setXXXp?我试q?臛_mysql,
oracle,sql server是可以直接set?
好了,我们先看一个例子如何写入文件到数据?
数据l构:
create table test(
name varchar(200),
content BLOB
);
File f = new File("a.exe";//先生成File对象是ؓ了取得流的长?FileInputStram可以直接
//传入文g路径
InputStream in = new InputStream(new FileInputStream(f));
PreparedStatement ps = conn.prepareStatement("insert into test (?,?)";
ps.setString(1,"a.exe");
ps.setBinaryStream(2,in,(int)f.length());
ps.executeUpdate();
f的长度一定要做从long到int的{?SUN的文档中好几版都没有改过?p么简?当然,不同?br>数据库存本n要设|它允许的最大长?MYSQL默认只能?M的文?要修改参数原能存更大的文?
如果要从数库中取得文?
PreparedStatement ps = conn.prepareStatement("select * from test where name=?");
ps.setString(1,"a.exe";
ResultSet rs = ps.executeQuery();
if(rs.next()){
InputStream in = rs.getBinaryStream("content";
}
得到in对象?你可以进行Q何处?写向文g和写向页面只是out对象不同而已:
写向文g:
DateOutputStream out = new DateOutputStream(new FileOutputStream("b.exe");
写向面:
response.reset();
response.setContType("cd";
ServletOutputSreamt out = response.getOutputSream();
得到out对象?可以输Z:
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf)) >0)
out.write(buf,0,len);
in.close();
out.close();
对于向页面输?要设|什么样的ContType,要看你想如何输出,如果你想让对方下?p?br>"application/octet-stream",q样即是文?图象都会下蝲而不会在览器中打开.如果你要?br>在浏览器中打开,p讄相应的类?q要在容器的配置文g中设|支持这U文档类型的输出,?br>对于很多格式的文?到底要输Z么类?其实是HTTP的MIME?比如囄:image/gif,当然你如
果你的文件扩展名(ext)不确?你也不要用if(ext.equals("gif")......q样来判?我教你一?br>技?我之所以说是技?是我没有在别的地方发现有人用q种Ҏ,Ҏ来说我是l对不会把别人的
Ҏ拿来说是我的技巧的:
构造一个filecd的URL,我们知道URL目前JAVA可以支持HTTP,FTP,MAILTO,FILE,LDAP{?从FILEcd
的URL可以得到它的MIME:
URL u = new URL("file://a.exe";
String mime = u.openConnection().getContentType();
q样你就可以直接response.setContType(mime);而不用一个一个类型判断了.
好了,大对象存储就说到q儿,不同的数据仍然和些特D的规定,不在此一一列D?