Written on 12:18 上午 by Yu Lai
Ref: http://msnlite.org/thread-365-1-1.html
C++是使用pointer來靈活方便地控制memory與instance的,這是它強大的原因之一,
但它缺乏像Java一樣的Garbage Collector機制來回收instance,
因此Programmer必須要自己手動delete掉new出來的instance。
這在軟體規模小的時候還好,但在規模大、多人協同工作、多線程環境加入時,
往往memory與instance的分配和釋放變的越來越難控制。
因此Boost C++ Libraries提供了shared_ptr,
shared_ptr實際上是一個Template Class,
透過instance成不同Class,為Class提供Pointer操作。
例如:
shared_ptr<int> p1(new int);
shared_ptr<int> p2=p1;
這樣p1和p2都可以point到int。
shared_ptr Class內有2個variable,一個是原始pointer,
可以用get()取得,用reset(T* p)可以重新設置。
另一個是instance的引用次數,其值可以用use_count()獲得。
它會隨著引用的shared_ptr來增加,當shared_ptr銷毀時,
引用次數也會減少,當減少到0時,shared_ptr會呼叫delete function來delete instance。
使用方法:
shared_ptr<Object> p1(new Object); //Use constructor
shared_ptr<Object> p2=p1; //assign
shared_ptr<Object> p3.reset(p1); //reset function
p1.reset(); //放棄引用
另外shared_ptr也可以配合malloc()來使用,但這樣point到的空間沒辦法被正常釋放掉,
必須額外定義delete function才行,malloc()的delete function即為free()。
所以使用如下:
shared_ptr p(malloc(100),free);
最後,我想坦白說句我心理的話: "C++搞成這樣,實在只是讓人覺得更難用而已。= ="
Posted in
技術,
C++,
Java
|
Written on 10:00 上午 by Yu Lai
最近在幫Pinter弄系統,發現Tomcat偶爾會噴OutOfMemory
的Exception出來,而在Console中也沒有辦法Trace出怎麼發生的。
Survey了一下才發現,原來除了存取大量的資料外,在Tomcat中使用
Singleton Pattern會有這類問題。
原因如下:
Hard references to classes can prevent the garbage collector from reclaiming the memory allocated for them when a ClassLoader is discarded. This will occur on JSP recompilations, and webapps reloads. If these operations are common in a webapp having these kinds of problems, it will be a matter of time, until the PermGen space gets full and an Out Of Memory is thrown.
而解決方法有三種:
Workaround 1: Move the class to another classloader
This workaround is for the case this class should be shared between webapps, or if the server will contain only one webapp. That is, we need to use the same instance across several webapps in the same server, or there is no need to worry about it. In this case, the class will need to be deployed on a shared classloader. This means this class must be in the shared/lib or shared/classes directory.
This way, the class will be loaded by a parent classloader, and not by the webapp classloader itself, so no resources need to be reclaimed on webapp reloadings.
This workaround may not always fit well with your code or design. In particular, care must be taken to avoid the singleton to keep references to classes loaded through the webapp classloader, because such references would prevent the classloader from being deallocated. A servlet context listener could be used to get rid of those references before the context is destroyed.
Workaround 2: Use commons-discovery
If you need to have a singleton instance for each webapp, you could use commons-discovery. This library provides a class named DiscoverSingleton that can be used to implement singletons in your webapp.
For using it, the class to be used as singleton will need to implement an interface (SPI) with the methods to be used. The following code is an example of usage of this library:
MyClass instance = DiscoverSingleton.find(MyClass.class, MyClassImpl.class.getName());
It is important, for this library to work correctly, to not keep static references to the returned instances.
Just by using this syntax, you get the following advantages:
Any class could be used as a singleton, as long as it implements an SPI interface.
Your singleton class has been converted into a replaceable component in your webapp, so you can "plug-in" a different implementation whenever you want.
But only this does not make for a workaround. The most important advantage is the DiscoverSingleton.release() method, that releases all references to instantiated singletons in the current classloader. A call to this method could be placed into a ServletContextListener, into its contextDestroyed() method.
That is, with a ServletContextListener simple implementation like the following:
public class SingletonReleaser implements ServletContextListener {
public contextInitialized(ServletContextEvent event) { }
public contextDestroyed(ServletContextEvent event) {
DiscoverSingleton.release();
}
}
we could release all cached references to the instantiated singletons. Of course, this listener should be registered on the web.xml descriptor before any other listener that could use a singleton.
Workaround 3: Use ServletContext attributes
This refactoring will work well provided the ServletContext instance is available, as a local variable or as a parameter.
It will be more efficient than using commons-discovery, but has the disadvantage of making your code depend on the web layer (ServletContext class). Anyway, I have found out that, in some cases, it is a reasonable approach.
There are many ways to do this refactoring, so I will just present one implementation that works well for me:
Create the following ServletContextListener:
public class SingletonFactory implements ServletContextListener {
public static final String MY_CLASS = "...";
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event) {
ServletContext ctx = event.getServletContext();
ctx.setAttribute(MY_CLASS, new MyClass());
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent event) {
ctx.setAttribute(MY_CLASS, null);
}
/**
* Optional method for getting the MyClass singleton instance.
*/
public static MyClass getMyClassInstance(ServletContext ctx) {
return (MyClass)ctx.getAttribute(MY_CLASS);
}
}
Register the listener in the web.xml descriptor
Replace the calls to MyClass.getInstance() by:
MyClass instance = (MyClass)ctx.getAttribute(SingletonFactory.MY_CLASS);
/* or, if implemented:
MyClass instance = SingletonFactory.getMyClassInstance(ctx);
*/
Posted in
技術,
Java
|