私は現在、次の属性を持つマシンでJavaWebアプリケーションを開発しています。
- Ubuntu-Server Edition Linux12.0464ビット
- SunjavaJDKバージョン7
- Apache Tomcat 7.0.30
- Netbeans IDE、バージョン7.1.2
私のプロジェクトは、共有メモリ内オブジェクトを維持するSOAPWebサービスインターフェイスで構成されています。オブジェクトをすべてのスレッドで表示できるようにするために、シングルトンを開発しました。アプリケーションのコードを以下に投稿します。
@WebService()
public class ETL_WS {
private Singleton CAP_offer_coupon_map;
public ETL_WS() { }
/**
* This method adds a single coupon record to the memory map.
*/
@WebMethod
synchronized public int singleCouponLoad(@WebParam(name =
"CouponID") long coupon_id,
@WebParam(name = "ProductCategoryID") long product_category_id,
@WebParam(name = "DateTo") Date dateTo,
@WebParam(name = "LocationID") Location location_id) {
Coupon _c = new Coupon(coupon_id, product_category_id, dateTo);
if(location_id != null)
_c.setLocation(location_id);
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
Coupon _tmp = _data.getCoupon(coupon_id);
if(_tmp == null)
return -1;
_data.insertCoupon(_c);
return 0;
}
/**
* This method adds a single offer record to the memory map.
*/
@WebMethod
synchronized public int singleOfferLoad(@WebParam(name =
"OfferID") long offer_id,
@WebParam(name = "ProductCategoryID") long product_category_id,
@WebParam(name = "DateTo") Date dateTo,
@WebParam(name = "LocationID") Location location_id) {
Offer _o = new Offer(offer_id, product_category_id, dateTo);
if(location_id != null)
_o.setLocation(location_id);
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
Offer _tmp = _data.getOffer(offer_id);
if(_tmp == null)
return -1;
_data.insertOffer(_o);
return 0;
}
@WebMethod
synchronized public String getAllCoupons() {
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
HashMap<Long, Coupon> _c = _data.getCoupons_map();
return _c.toString();
}
@WebMethod
synchronized public String getAllOffers() {
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
HashMap<Long, Offer> _o = _data.getOffers_map();
return _o.toString();
}
@WebMethod
synchronized public long getProductIdFromCouponId(@**WebParam(name
= "CouponID") long coupon_id) {
long _product_id = -1;
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
Coupon _c = _data.getCoupon(coupon_id);
if(_c != null)
_product_id = _c.getCoupon_id();
return _product_id;
}
@WebMethod
synchronized public long getProductIdFromOfferId(@WebParam(name = "OfferID") long
offer_id) {
long _product_id = -1;
CAP_CouponOfferCollection _data = CAP_offer_coupon_map.getModel();
Offer _o = _data.getOffer(offer_id);
if(_o != null)
_product_id = _o.getOffer_id();
return _product_id;
}
}
シングルトンラッパークラスを以下に示します。
public class Singleton {
private static boolean _instanceFlag = false;
private static final Singleton _instance = new Singleton();
private static CAP_CouponOfferCollection _data;
private Singleton() {
_data = new CAP_CouponOfferCollection();
_instanceFlag = true;
}
public static synchronized CAP_CouponOfferCollection getModel() {
if(_instanceFlag == false) {
_data = new CAP_CouponOfferCollection();
_instanceFlag = true;
}
return _data;
}
}
CAP_CouponOfferCollectionクラスを以下に示します。
public class CAP_CouponOfferCollection {
private HashMap<Long, Coupon> _coupons_map;
private HashMap<Long, ArrayList<Long>> _product_to_coupons_map;
private HashMap<Long, Offer> _offers_map;
private HashMap<Long, ArrayList<Long>> _product_cat_to_offers_map;
private static long _creation_time;
public CAP_CouponOfferCollection() {
_creation_time = System.currentTimeMillis();
System.out.println("Creation of CAP_CouponOffer object: " +
_creation_time);
}
synchronized public void insertCoupon(Coupon newCoupon) {
if(_coupons_map == null) {
_coupons_map = new HashMap<Long, Coupon>();
_product_to_coupons_map =
new HashMap<Long, ArrayList<Long>>();
}
Long key = newCoupon.getCoupon_id();
if(!_coupons_map.containsKey(key)) {
_coupons_map.put(key, newCoupon);
key = newCoupon.getProductCategory_id();
if(_product_to_coupons_map.containsKey(key)) {
ArrayList<Long> _c_list = _product_to_coupons_map.get(key);
_c_list.add(newCoupon.getCoupon_id());
_product_to_coupons_map.remove(key);
_product_to_coupons_map.put(key, _c_list);
}else {
ArrayList<Long> _c_list = new ArrayList<Long>();
_c_list.add(newCoupon.getCoupon_id());
_product_to_coupons_map.put(key, _c_list);
}
}
}
synchronized public void insertOffer(Offer newOffer) {
if(_offers_map == null) {
_offers_map = new HashMap<Long, Offer>();
_product_cat_to_offers_map =
new HashMap<Long, ArrayList<Long>>();
}
Long key = newOffer.getOffer_id();
if(!_offers_map.containsKey(key)) {
_offers_map.put(key, newOffer);
key = newOffer.getProductCategory_id();
if(_product_cat_to_offers_map.containsKey(key)) {
ArrayList<Long> _o_list = _product_cat_to_offers_map.get(key);
_o_list.add(newOffer.getOffer_id());
_product_cat_to_offers_map.remove(key);
_product_cat_to_offers_map.put(key, _o_list);
}else {
ArrayList<Long> _o_list = new ArrayList<Long>();
_o_list.add(newOffer.getOffer_id());
_product_cat_to_offers_map.put(key, _o_list);
}
}
}
synchronized public void removeCoupon(long couponId) {
Coupon _c;
Long key = new Long(couponId);
if(_coupons_map != null && _coupons_map.containsKey(key)) {
_c = (Coupon) _coupons_map.get(key);
_coupons_map.remove(key);
Long product = new Long(_c.getCoupon_id());
ArrayList<Long> _c_list =
(ArrayList<Long>) _product_to_coupons_map.get(product);
_c_list.remove(key);
_product_to_coupons_map.remove(product);
_product_to_coupons_map.put(product, _c_list);
}
}
synchronized public void removeOffer(long offerId) {
Offer _o;
Long key = new Long(offerId);
if(_offers_map != null && _offers_map.containsKey(key)) {
_o = (Offer) _offers_map.get(key);
_offers_map.remove(key);
Long product = new Long(_o.getOffer_id());
ArrayList<Long> _o_list =
(ArrayList<Long>) _product_cat_to_offers_map.get(product);
_o_list.remove(key);
_product_cat_to_offers_map.remove(product);
_product_cat_to_offers_map.put(product, _o_list);
}
}
synchronized public Coupon getCoupon(long CouponID) {
Long key = new Long(CouponID);
if(_coupons_map != null && _coupons_map.containsKey(key)) {
Coupon _c = (Coupon) _coupons_map.get(key);
Date _now = new Date();
if(_now.compareTo(_c.getDateTo()) > 0) {
this.removeCoupon(CouponID);
return null;
}
return (Coupon) _coupons_map.get(key);
}else
return null;
}
synchronized public Offer getOffer(long OfferID) {
Long key = new Long(OfferID);
if(_offers_map != null && _offers_map.containsKey(key)) {
Offer _o = (Offer) _offers_map.get(key);
Date _now = new Date();
if(_now.compareTo(_o.getDateTo()) > 0) {
this.removeOffer(OfferID);
return null;
}
return (Offer) _offers_map.get(key);
}else
return null;
}
synchronized public ArrayList<Long> getCoupons(long ProductID) {
Long key = new Long(ProductID);
if(_product_to_coupons_map != null && _product_to_coupons_map.containsKey(key))
{
ArrayList<Long> _c_list =
(ArrayList<Long>) _product_to_coupons_map.get(key);
Iterator itr = _c_list.iterator();
while(itr.hasNext()) {
Long l = (Long) itr.next();
if(this.getCoupon(l.longValue()) == null)
_c_list.remove(l.intValue());
}
_product_to_coupons_map.remove(key);
_product_to_coupons_map.put(key, _c_list);
return _c_list;
}else
return null;
}
synchronized public ArrayList<Long> getOffers(long ProductID) {
Long key = new Long(ProductID);
if(_product_cat_to_offers_map != null &&
_product_cat_to_offers_map.containsKey(key)) {
ArrayList<Long> _o_list = _product_cat_to_offers_map.get(key);
Iterator itr = _o_list.iterator();
while(itr.hasNext()) {
Long l = (Long) itr.next();
if(this.getOffer(l.longValue()) == null)
_o_list.remove(l.intValue());
}
_product_cat_to_offers_map.remove(key);
_product_cat_to_offers_map.put(key, _o_list);
return _o_list;
}else
return null;
}
synchronized public HashMap<Long, Coupon> getCoupons_map() {
return _coupons_map;
}
synchronized public void setCoupons_map(HashMap<Long, Coupon> _coupons_map) {
this._coupons_map = _coupons_map;
}
synchronized public static long getCreation_time() {
return _creation_time;
}
synchronized public void cleanup_offers() {
if(_product_cat_to_offers_map != null) {
Set _offers_key_set = _product_cat_to_offers_map.keySet();
Iterator itr = _offers_key_set.iterator();
while(itr.hasNext()) {
Long l = (Long) itr.next();
this.getOffers(l.longValue());
}
}
}
synchronized public void cleanup_coupons() {
if(_product_to_coupons_map != null) {
Set _coupons_key_set = _product_to_coupons_map.keySet();
Iterator itr = _coupons_key_set.iterator();
while(itr.hasNext()) {
Long l = (Long) itr.next();
this.getCoupons(l.longValue());
}
}
}
}
問題は、上記のアプリケーション(名前はETL_Procedures)をApache Tomcatにデプロイすると、次の重大なログエントリが取得されることです。
SEVERE: The web application [/ETL_Procedures] appears to have started a thread named [maintenance-task-executor-thread-1] but has failed to stop it. This is very likely to create a memory leak.
Oct 03, 2012 5:35:03 PM org.apache.catalina.loader.WebappClassLoadercheckThreadLocalMapForLeaks
SEVERE: The web application [/ETL_Procedures] created a ThreadLocal with key of type [org.glassfish.gmbal.generic.OperationTracer$1] (value [org.glassfish.gmbal.generic.OperationTracer$1@4c24821]) and a value of type [java.util.ArrayList] (value [[]]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Oct 03, 2012 5:35:03 PM org.apache.catalina.loader.WebappClassLoadercheckThreadLocalMapForLeaks
SEVERE: The web application [/ETL_Procedures] created a ThreadLocal with key of type [com.sun.xml.bind.v2.ClassFactory$1] (value [com.sun.xml.bind.v2.ClassFactory$1@6f0d70f7]) and a value of type [java.util.WeakHashMap] (value [{class com.sun.xml.ws.runtime.config.TubeFactoryList=java.lang.ref.WeakReference@5b73a116, class javax.xml.bind.annotation.adapters.CollapsedStringAdapter=java.lang.ref.WeakReference@454da42, class com.sun.xml.ws.runtime.config.MetroConfig=java.lang.ref.WeakReference@5ec52546, class com.sun.xml.ws.runtime.config.TubeFactoryConfig=java.lang.ref.WeakReference@61124745, class java.util.ArrayList=java.lang.ref.WeakReference@770534cc, class com.sun.xml.ws.runtime.config.Tubelines=java.lang.ref.WeakReference@76cd7a1f, class javax.xml.bind.annotation.W3CDomHandler=java.lang.ref.WeakReference@2c0cc628, class com.sun.xml.ws.runtime.config.TubelineDefinition=java.lang.ref.WeakReference@7aa582af}]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Oct 03, 2012 5:35:03 PM org.apache.catalina.loader.WebappClassLoadercheckThreadLocalMapForLeaks
SEVERE: The web application [/ETL_Procedures] created a ThreadLocal with key of type [com.sun.xml.bind.v2.runtime.Coordinator$1] (value [com.sun.xml.bind.v2.runtime.Coordinator$1@826ee11]) and a value of type [java.lang.Object[]] (value [[Ljava.lang.Object;@33d7a245]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Oct 03, 2012 5:35:03 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SEVERE: The web application [/ETL_Procedures] created a ThreadLocal with key of type [org.glassfish.gmbal.generic.OperationTracer$1] (value [org.glassfish.gmbal.generic.OperationTracer$1@4c24821]) and a value of type [java.util.ArrayList] (value [[]]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
これらのメモリリークの原因は本当にわかりません。私の質問は次のとおりです。
- 誰かが私のWebサービスの問題が何であるかを疑うことができますか?メモリリークの原因がシングルトンオブジェクトである場合、アプリケーションの要件を満たし、メモリリークを回避するために他に何ができるでしょうか。
- スレッドを監視するために使用できるツールはありますか?また、これらの重大なメッセージの正確な原因は何ですか?
アプリケーションを長期間デプロイすると、次のメッセージが表示されたIllegalStateExceptionが発生します。
INFO: Illegal access: this web application instance has been stopped already. Could not load com.sun.xml.ws.rx.rm.localization.LocalizationMessages. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1600) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) at com.sun.xml.ws.rx.rm.runtime.sequence.SequenceMaintenanceTask.run(SequenceMaintenanceTask.java:81) at com.sun.xml.ws.commons.DelayedTaskManager$Worker.run(DelayedTaskManager.java:91) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722)
この例外の原因となる呼び出しパス全体を確認するにはどうすればよいですか?
お時間をいただきありがとうございました。長いメッセージをお詫び申し上げます。