/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.harmony.luni.platform; import java.lang.ref.ReferenceQueue; import java.lang.ref.Reference; import java.lang.ref.PhantomReference; import java.util.HashMap; import java.util.Map; /** * Abstract implementation for the OS memory spies. * */ abstract class AbstractMemorySpy implements IMemorySpy { // TODO: figure out how to prevent this being a synchronization bottleneck protected Map<PlatformAddress,AddressWrapper> memoryInUse = new HashMap<PlatformAddress, AddressWrapper>(); // Shadow to Wrapper protected Map<Reference,PlatformAddress> refToShadow = new HashMap<Reference, PlatformAddress>(); // Reference to Shadow protected ReferenceQueue<Object> notifyQueue = new ReferenceQueue<Object>(); final class AddressWrapper { final PlatformAddress shadow; final PhantomReference<PlatformAddress> wrAddress; volatile boolean autoFree = false; AddressWrapper(PlatformAddress address) { super(); this.shadow = address.duplicate(); this.wrAddress = new PhantomReference<PlatformAddress>(address, notifyQueue); } } public AbstractMemorySpy() { super(); } public void alloc(PlatformAddress address) { AddressWrapper wrapper = new AddressWrapper(address); synchronized (this) { memoryInUse.put(wrapper.shadow, wrapper); refToShadow.put(wrapper.wrAddress, wrapper.shadow); } } public boolean free(PlatformAddress address) { AddressWrapper wrapper; synchronized (this) { wrapper = memoryInUse.remove(address); // BEGIN android-added if (wrapper != null) { refToShadow.remove(wrapper.wrAddress); } // END android-added } if (wrapper == null) { // Attempt to free memory we didn't alloc System.err .println("Memory Spy! Fixed attempt to free memory that was not allocated " + address); //$NON-NLS-1$ } return wrapper != null; } public void rangeCheck(PlatformAddress address, int offset, int length) throws IndexOutOfBoundsException { // Do nothing } /* * (non-Javadoc) * * @see org.apache.harmony.luni.platform.struct.IMemorySpy#autoFree(org.apache.harmony.luni.platform.struct.PlatformAddress) */ public void autoFree(PlatformAddress address) { AddressWrapper wrapper; synchronized (this) { wrapper = memoryInUse.get(address); } if (wrapper != null) { wrapper.autoFree = true; } } protected void orphanedMemory(Reference ref) { AddressWrapper wrapper; synchronized (this) { PlatformAddress shadow = refToShadow.remove(ref); wrapper = memoryInUse.get(shadow); if (wrapper != null) { // There is a leak if we were not auto-freeing this memory. if (!wrapper.autoFree) { System.err .println("Memory Spy! Fixed memory leak by freeing " + wrapper.shadow); //$NON-NLS-1$ } wrapper.shadow.free(); } } ref.clear(); } }