IN that case, please watch any additions to Jira related to this, and provide us with as much feedbacl as possible.
Werner James wrote: > Werner, > > Thanks for you response. I agree re: synchronized collections, making > the methods thread-safe makes sense. We will be more than happy to test > and changes/enhancements you make. > > Regards, > > James. > > Werner Guttmann wrote: >> James, >> Whilst make the collection synchronized is definitely not an option >> (as explained by Steven in the same thread), making the missing >> methois that access the collection(s) in a write mode is a goal. >> >> We'd definitely appreciate your help in this context, and the more of >> a test environment you have, the better for us and yourself. >> >> Steven, shall we create a new Jira issue asking ourselves to have a >> look at this (making the remaining write methods thread-safe) ? >> Regards >> Werner >> >>> -----Ursprüngliche Nachricht----- >>> Von: [EMAIL PROTECTED] >>> [mailto:[EMAIL PROTECTED] Im Auftrag von James >>> Gesendet: Mittwoch, 21. März 2007 13:50 >>> An: [email protected] >>> Betreff: Re: Re: AW: AW: [castor-user] [XML] XMLClassDescriptorResolver >>> XMLFieldDescriptorImpl cache possible memory leak >>> >>> Hi All, >>> >>> I've just joined the mailing list because I saw a conversation between >>> Adam Chesney and the Castor development team in the archives, and >>> thought I would add my two cents. :) >>> >>> Below is a link to the last email on this thread: >>> >>> http://archive.castor.codehaus.org/user/00b501c767ea%24da8a1880%240a84010a >>> >>> %40zultan >>> >>> We use Castor in much the same way as Adam: 100's of thousands of Castor >>> generated beans, and which get loaded at runtime depends very much on >>> the user/runtime profile of our application. I agree with Adam that >>> initialising the XMLClassDescriptorResolver at startup is not really a >>> useful solution - we would have to maintain a very messy (and error >>> prone) configuration to track individual bean classes in what is a huge >>> application, and it would also cause unnecessarily high memory usage. >>> >>> Although I can't be sure, looking at the source code for >>> XMLClassDescriptorResolverImpl.DescriptorCache in Castor 1.1, I think >>> changing the non-threadsafe collections to synchronized ones would >>> probably do the trick. In any case, I'm sure making a thread-safe >>> XMLClassDescriptorResolver implementation would not be that difficult >>> and we will be more than happy to contribute codes and run some highly >>> concurrent tests if the Castor developers agree that this is the best >>> way forward. >>> >>> My 2 cents! >>> >>> Kind regards, >>> >>> James. >>> >>> P.S. Below is a short investigation into the possible effects of using >>> HashMap in a multi-threaded environment in a non-thread-safe way. >>> >>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> >>> As Adam's colleague has done, I have isolated the HashMap race condition >>> (in both Java 1.4 and 1.5). The problem happens with concurrent writes >>> to the map, no reads are necessary to recreate the problem (though they >>> also have a race condition when there are concurrent writes). >>> >>> Below is the source for HashMap.put: >>> >>> <code> >>> >>> public V put(K key, V value) { >>> if (key == null) >>> return putForNullKey(value); >>> int hash = hash(key.hashCode()); >>> int i = indexFor(hash, table.length); >>> for (Entry<K,V> e = table[i]; e != null; e = e.next) { >>> Object k; >>> if (e.hash == hash && ((k = e.key) == key || >>> key.equals(k))) { >>> V oldValue = e.value; >>> e.value = value; >>> e.recordAccess(this); >>> return oldValue; >>> } >>> } >>> >>> modCount++; >>> addEntry(hash, key, value, i); >>> return null; >>> } >>> >>> </code> >>> >>> As you can see, the for loop will only complete when "e != null" - that >>> is to say, that the last entry in the table (Entry[]) is null. The call >>> to HashMap.addEntry near the end of the method calls the HashMap.resize >>> if the size of the array that backs the map needs to be resized. It >>> seems that a circular reference inside one of the bins _can_ occur and >>> _might_ cause a race condition. See the code for HashMap.transfer below: >>> >>> <code> >>> >>> void transfer(Entry[] newTable) { >>> Entry[] src = table; >>> int newCapacity = newTable.length; >>> for (int j = 0; j < src.length; j++) { >>> Entry<K,V> e = src[j]; >>> if (e != null) { >>> src[j] = null; >>> do { >>> Entry<K,V> next = e.next; >>> int i = indexFor(e.hash, newCapacity); >>> e.next = newTable[i]; >>> newTable[i] = e; >>> e = next; >>> } while (e != null); >>> } >>> } >>> } >>> >>> </code> >>> >>> I am able to recreate the problem with the code below. If the HashMap is >>> initialised to "maxSize", I have not seen the race condition occur, >>> however, if it is initalised to 1 (as in the code below), the race >>> condition happens relatively frequently. >>> >>> <code> >>> >>> /** >>> * HashMapTester >>> * Show a race condition HashMap >>> */ >>> public class HashMapTester{ >>> >>> /** >>> * @param args >>> */ >>> public static void main(String[] args) { >>> new HashMapTester().run(); >>> } >>> >>> public void run() { >>> int max = 10; >>> int maxSize = 100000; >>> List<HashMapWriter> writers = new >>> ArrayList<HashMapWriter>(max); >>> Map<String,String> m = new HashMap<String,String>(1); >>> for(int i = 0; i < max; i++) { >>> HashMapWriter writer = new HashMapWriter(m,maxSize); >>> writers.add(writer); >>> writer.start(); >>> System.out.println("Num writers created: " + (i + 1)); >>> } >>> } >>> >>> >>> class HashMapWriter extends Thread{ >>> Random r = new Random(System.currentTimeMillis()); >>> Map<String, String> m = null; >>> int maxSize =-1; >>> @Override >>> public void run() { >>> while(true) { >>> if(m.size() < maxSize || m.size() == 0) { >>> String something = String.valueOf(m.size()); >>> m.put(something,something); >>> if(m.size() % 100 == 0) { >>> System.out.println("Map size is now: " + >>> m.size()); >>> } >>> }else { >>> String something = >>> String.valueOf(r.nextInt(m.size())); >>> m.put(something, something); >>> try { >>> Thread.sleep(r.nextInt(10) +1 ); >>> } catch (InterruptedException e) { >>> e.printStackTrace(); >>> } >>> } >>> >>> } >>> } >>> public HashMapWriter(Map<String, String> m, int maxSize) { >>> this.m = m; >>> this.maxSize = maxSize; >>> } >>> } >>> } >>> >>> </code> >>> >>> --------------------------------------------------------------------- >>> To unsubscribe from this list please visit: >>> >>> http://xircles.codehaus.org/manage_email >> >> >> --------------------------------------------------------------------- >> To unsubscribe from this list please visit: >> >> http://xircles.codehaus.org/manage_email >> > > --------------------------------------------------------------------- > To unsubscribe from this list please visit: > > http://xircles.codehaus.org/manage_email > --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email

