Index: working_vm/vm/port/include/port_malloc.h =================================================================== --- working_vm/vm/port/include/port_malloc.h (revision 644245) +++ working_vm/vm/port/include/port_malloc.h (working copy) @@ -14,26 +14,148 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @author Evgueni Brevnov +/** + * @author Evgueni Brevnov, Andrey Yakushev * @version $Revision: 1.1.2.1.4.4 $ - */ + */ #ifndef _PORT_MALLOC_H_ #define _PORT_MALLOC_H_ +#include "port_general.h" #ifdef WIN32 -#include + #include #else -#include + #include #endif -// FIXME -// Very basic memory allocation utilities +#ifdef __cplusplus + #define INLINE inline +#else + #ifdef WIN32 + #define INLINE __forceinline + #else + #define INLINE static + #endif +#endif -#define STD_FREE(p) free(p) -#define STD_MALLOC(s) malloc(s) -#define STD_CALLOC(n, s) calloc(n, s) -#define STD_REALLOC(p, s) realloc(p, s) -#define STD_ALLOCA(s) alloca(s) +/** + * If defined then debug variants of memory allocation functions (malloc, + * free etc.) are used. + * They provides additional functionaliy, like detailed statistic and + * memory leackage control. + */ +//#define _MEMMGR +/** Pool name for java.lang.management usage */ +#define NATIVE_POOL_NAME "Native Memory Pool" + +/** Defailt file name for feporting the memory usage informaion */ +#define MALLOC_LOG_FILE_NAME "malloc.log" + +#ifdef _MEMMGR + /** If defined then all native allocations and deallocations will be loged in MALLOC_LOG_FILE_NAME */ + #define _MEMMGR_LOG + /** If defined then report of currently unfreed memory will be loged in MALLOC_LOG_FILE_NAME */ + #define _MEMMGR_REPORT + + #ifdef __cplusplus + extern "C" { + #endif + + /** + * Wrapper for standard free function. Used if _MEMMGR is defined. + * Provides checking for suquential call with the same address, and memory leackage. + * @param[in] APTR - address of memory block which would be checked ant passed + * to free function + * @param[in] file_name - file name where port_free is called + * @param[in] file_line - file line number where port_free is called + */ + APR_DECLARE(void) port_free(void *APTR, char *file_name, int file_line); + + /** + * Wrapper for standard malloc function. Used if _MEMMGR is defined. + * Provides storing arguments info about this call for statistics and additinal control, like + * memory leackage. + * @param[in] NBYTES - size in bytes passed to malloc function + * @param[in] file_name - file name where port_malloc is called + * @param[in] file_line - file line number where port_malloc is called + */ + APR_DECLARE(void*) port_malloc(size_t NBYTES, char *file_name, int file_line); + + /** + * Initiates memory control system. Used if _MEMMGR is defined. All memory allocation + * and releasing calls would be monitored futher. Explicit initialization is requirred + * for controling memory management during defined execution range. + */ + void start_monitor_malloc(); + + /** + * Stops memory control system. Used if _MEMMGR is defined. Provides generation of detailed + * statistics at this place. + */ + void report_leaked_malloc(); + + /** + * Returns size of memory in bytes currently used by port_malloc. + * @return size of memory in bytes currently used by port_malloc. + */ + size_t port_mem_used_size(); + + /** + * Returns size of memory in bytes currently reserved by port_malloc. + * @return size of memory in bytes currently reserved by port_malloc. + */ + size_t port_mem_reserved_size(); + + /** + * Returns size of committed memory in bytes currently used by port_malloc. + * @return size of committed memory in bytes currently used by port_malloc. + */ + size_t port_mem_committed_size(); + + /** + * Returns maximum size of memory in bytes which could be used by port_malloc. + * @return maximum size of memory in bytes which could be used by port_malloc. + */ + size_t port_mem_max_size(); + + #ifdef _MEMMGR_LOG + + #define _MEMMGR_LOG_OR_REPORT + #define MEMMGR_LOG(m) fprintf m; + #else + #define MEMMGR_LOG(m) + #endif + + #ifdef _MEMMGR_REPORT + #define _MEMMGR_LOG_OR_REPORT + #endif + + #ifdef __cplusplus + } + #endif + + + #ifdef STRESS_MALLOC + // TODO: implement here small preallocated malloc for out of memory conditions + #define STD_FREE(p) free(p) + #define STD_MALLOC(s) malloc(s) + #define STD_CALLOC(n, s) calloc(n, s) + #define STD_REALLOC(p, s) realloc(p, s) + #define STD_ALLOCA(s) alloca(s) + #else // not defined STRESS_MALLOC + #define STD_FREE(p) port_free(p, __FILE__, __LINE__) + #define STD_MALLOC(s) port_malloc(s, __FILE__, __LINE__) + #define STD_CALLOC(n, s) calloc(n, s) + #define STD_REALLOC(p, s) realloc(p, s) + #define STD_ALLOCA(s) alloca(s) + #endif //STRESS_MALLOC +#else // not defined _MEMMGR + #define STD_FREE(p) free(p) + #define STD_MALLOC(s) malloc(s) + #define STD_CALLOC(n, s) calloc(n, s) + #define STD_REALLOC(p, s) realloc(p, s) + #define STD_ALLOCA(s) alloca(s) +#endif // _MEMMGR + #endif // _PORT_MALLOC_H_ Index: working_vm/vm/port/src/malloc/port_malloc_registrar.h =================================================================== --- working_vm/vm/port/src/malloc/port_malloc_registrar.h (revision 0) +++ working_vm/vm/port/src/malloc/port_malloc_registrar.h (revision 0) @@ -0,0 +1,122 @@ +/* + * 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. + */ +/** + * @author Andrey Yakushev + */ +#ifndef _PORT_MALLOC_REGISTRAR_H_ +#define _PORT_MALLOC_REGISTRAR_H_ + +#ifdef WIN32 + #include +#else + #include + #include +#endif + +#include +#include + +/** + * Memory block descriptor. + */ +class ChunkAttributes { +public: + /** Size of memory block */ + size_t size; + + /** file name where port_malloc is called */ + char *file_name; + + /** file line number where port_malloc is called */ + int file_line; + + /** + * Constructor for memory block descriptor. Initializes the field + * corresponding to arguments. + * @param[in] size - size in bytes + * @param[in] file_name - file name where this block is created + * @param[in] file_line - file line number where this block is created + */ + ChunkAttributes(size_t size, char *file_name, int file_line); +}; + +/** + * Map for storing memory block descriptions + * @see ChunkAttributes + */ +typedef std::map MallocCellar; + +/** + * Constant iterator for MallocCellar + * @see MallocCellar + */ +typedef std::map::const_iterator MallocCellarCI; + +/** + * Memory blocks registerer and statistics and problems reports provider + */ +class MallocRegistrar { +public: + /** + * Initializes log + */ + MallocRegistrar(); + + /** + * Stop and flash logging and registering + */ + ~MallocRegistrar(); + + /** + * Stores memory block info. + * @param[in] APTR - address of memory block which info would be stored + * @param[in] attr - memory block attributes for storing + * @see ChunkAttributes + */ + void register_chunk(void *APTR, ChunkAttributes* attr); + + /** + * Removes memory block info. + * @param[in] APTR - address of memory block which info would be removed + * @return attributes for removed memory block + * @see ChunkAttributes + */ + ChunkAttributes* unregister_chunk(void *APTR); + + /** + * Reports info for all currently stores memory blocks. If called at the end of + * program it contains list of leacked memory + */ + void report(); + + /** + * Report file handler for reporting. Defailt is defined in MALLOC_LOG_FILE_NAME + * @see MALLOC_LOG_FILE_NAME + */ + FILE *f_malloc_log; +private: + MallocCellar* mallocCellar; +#ifdef WIN32 + HANDLE mutex; +#else + pthread_mutex_t mutex; +#endif + +}; + + +#endif // _PORT_MALLOC_REGISTRAR_H_ Index: working_vm/vm/port/src/malloc/port_malloc.cpp =================================================================== --- working_vm/vm/port/src/malloc/port_malloc.cpp (revision 0) +++ working_vm/vm/port/src/malloc/port_malloc.cpp (revision 0) @@ -0,0 +1,117 @@ +/* + * 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. + */ +/** + * @author Andrey Yakushev + */ + + +#ifdef WIN32 +#include +#include +#include +#else +#include +#endif + +#include "port_malloc.h" +#include "port_malloc_registrar.h" + +#ifdef _MEMMGR + +extern "C" { + +#define MALLOC_LOG_FILE_NAME "malloc.log" + +static size_t mem_used_size = 0; +static size_t mem_committed_size = 0; +static size_t mem_reserved_size = 0; +static size_t mem_max_size = UINT_MAX; + +static MallocRegistrar* malloc_registrar; + +void start_monitor_malloc() { + malloc_registrar = new MallocRegistrar(); +} + +void report_leaked_malloc() { + malloc_registrar->report(); +} + +size_t port_mem_used_size() { + return mem_used_size; +} + +size_t port_mem_committed_size() { + return mem_committed_size; +} + +size_t port_mem_reserved_size() { + return mem_reserved_size; +} + +size_t port_mem_max_size() { + return mem_max_size; +} + + +APR_DECLARE(void*) port_malloc(size_t NBYTES, char *file_name, int file_line) { + void *result = malloc(NBYTES); + mem_used_size += NBYTES; + if (NULL != malloc_registrar) { + malloc_registrar->register_chunk(result, new ChunkAttributes(NBYTES, file_name, file_line)); + MEMMGR_LOG((malloc_registrar->f_malloc_log, + "malloc(%08u)=%08x from %s:%u\n", + NBYTES, + result, + file_name, + file_line)); + fflush(malloc_registrar->f_malloc_log); + } + return result; +} + +APR_DECLARE(void) port_free(void *APTR, char *file_name, int file_line) { + if (NULL == malloc_registrar) return; + ChunkAttributes* attr = malloc_registrar->unregister_chunk(APTR); + if (NULL == attr) { + if (NULL == APTR) return; + MEMMGR_LOG((malloc_registrar->f_malloc_log, + "Probably double free call for %08x from %s:%u\n", + APTR, + file_name, + file_line)); + fflush(malloc_registrar->f_malloc_log); + return; + } + free(APTR); + mem_used_size -= attr->size; + MEMMGR_LOG((malloc_registrar->f_malloc_log, + "free(%08x) at %s:%u\n malloc(%08u) from %s:%u\n current allocated size = %u\n", + APTR, + file_name, + file_line, + attr->size, + attr->file_name, + attr->file_line, + mem_used_size)); + fflush(malloc_registrar->f_malloc_log); + free(attr); +} + +} // extern "C" + +#endif // _MEMMGR Index: working_vm/vm/port/src/malloc/port_malloc_registrar.cpp =================================================================== --- working_vm/vm/port/src/malloc/port_malloc_registrar.cpp (revision 0) +++ working_vm/vm/port/src/malloc/port_malloc_registrar.cpp (revision 0) @@ -0,0 +1,99 @@ +/* + * 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. + */ +/** + * @author Andrey Yakushev + * @version $Revision: 1.1.2.1.4.5 $ + */ + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#include "port_malloc_registrar.h" +#include "log_macro.h" +#include "port_malloc.h" + +#ifdef _MEMMGR + +ChunkAttributes::ChunkAttributes(size_t size, char *file_name, int file_line) { + this->size = size; + this->file_name = file_name; + this->file_line = file_line; +} + +MallocRegistrar::MallocRegistrar() { +#ifdef _MEMMGR_LOG_OR_REPORT + f_malloc_log = fopen(MALLOC_LOG_FILE_NAME, "w"); + if( f_malloc_log == NULL) { + f_malloc_log = stdout; + }; + MEMMGR_LOG((f_malloc_log, "MallocRegistrar::MallocRegistrar invoked\n")); +#endif + mallocCellar = new MallocCellar(); + mutex = CreateMutex(NULL, FALSE, NULL); +} + +MallocRegistrar::~MallocRegistrar() { + MEMMGR_LOG((f_malloc_log, "MallocRegistrar::~MallocRegistrar invoked\n")); + fflush(f_malloc_log); + mutex = NULL; +} + +void MallocRegistrar::report() { + if (mutex == NULL) return; + WaitForSingleObject(mutex, 0); + MEMMGR_LOG((f_malloc_log, "Malloc leakage report:\n")); + for (MallocCellarCI i = mallocCellar->begin(); i!=mallocCellar->end(); ++i) { + if (NULL == i->second) { + fprintf(f_malloc_log, "NULL record in mallocCellar\n"); + return; + } + ChunkAttributes* attr = i->second; + fprintf(f_malloc_log, "unfreed pointer %08x size %08u from %s:%u\n", i->first, attr->size, attr->file_name, attr->file_line); + }; + fflush(f_malloc_log); + ReleaseMutex(mutex); +} + +void MallocRegistrar::register_chunk(void *APTR, ChunkAttributes* attr){ + if (mutex == NULL) return; + WaitForSingleObject(mutex, 0); + MallocCellarCI i = mallocCellar->find(APTR); + if (i != mallocCellar->end()) { // found + MEMMGR_LOG((f_malloc_log, "Such chunk already exists\n")); + fflush(f_malloc_log); + return; + } + (*mallocCellar)[APTR] = attr; + ReleaseMutex(mutex); +} + +ChunkAttributes* MallocRegistrar::unregister_chunk(void *APTR){ + if (mutex == NULL) return NULL; + WaitForSingleObject(mutex, 0); + MallocCellarCI i = mallocCellar->find(APTR); + if (i == mallocCellar->end()) return NULL; // not found + ChunkAttributes* result = i->second; + mallocCellar->erase(APTR); + ReleaseMutex(mutex); + return result; +} + +#endif // _MEMMGR Index: working_vm/vm/vmi/src/j9vmls.cpp =================================================================== --- working_vm/vm/vmi/src/j9vmls.cpp (revision 644245) +++ working_vm/vm/vmi/src/j9vmls.cpp (working copy) @@ -18,9 +18,9 @@ * @author Euguene Ostrovsky * @version $Revision: 1.1.2.1.4.5 $ */ -#include "hyvmls.h" #include "vm_trace.h" +#include "hyvmls.h" UDATA JNICALL HYVMLSAllocKeys(JNIEnv *env, UDATA *pInitCount,...) Index: working_vm/vm/vmcore/src/jni/jni.cpp =================================================================== --- working_vm/vm/vmcore/src/jni/jni.cpp (revision 644245) +++ working_vm/vm/vmcore/src/jni/jni.cpp (working copy) @@ -56,6 +56,7 @@ #include "stack_trace.h" #include "finalizer_thread.h" #include "ref_enqueue_thread.h" +#include "port_malloc.h" #ifdef _IPF_ #include "stub_code_utils.h" @@ -451,6 +452,10 @@ if (status != JNI_OK) return status; +#ifdef _MEMMGR + start_monitor_malloc(); +#endif + apr_thread_mutex_lock(GLOBAL_LOCK); // TODO: only one VM instance can be created in the process address space. @@ -1510,12 +1515,16 @@ status = vm_destroy(java_vm, java_thread); // Destroy VM environment. - delete java_vm->vm_env; + java_vm->vm_env->~Global_Env(); java_vm->vm_env = NULL; // Destroy VM pool. apr_pool_destroy(java_vm->pool); +#ifdef _MEMMGR_REPORT + report_leaked_malloc(); +#endif + return status; } Index: working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryPoolMXBeanImpl.cpp =================================================================== --- working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryPoolMXBeanImpl.cpp (revision 644245) +++ working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryPoolMXBeanImpl.cpp (working copy) @@ -31,6 +31,7 @@ #include #include "org_apache_harmony_lang_management_MemoryPoolMXBeanImpl.h" #include "environment.h" +#include "port_malloc.h" /* Native methods */ @@ -38,7 +39,7 @@ * Method: org.apache.harmony.lang.management.MemoryPoolMXBeanImpl.getCollectionUsageImpl()Ljava/lang/management/MemoryUsage; */ JNIEXPORT jobject JNICALL -Java_org_apache_harmony_lang_management_MemoryPoolMXBeanImpl_getCollectionUsageImpl(JNIEnv *jenv_ext, jobject) +Java_org_apache_harmony_lang_management_MemoryPoolMXBeanImpl_getCollectionUsageImpl(JNIEnv *jenv_ext, jobject this_been) { // TODO implement this method stub correctly TRACE2("management","getCollectionUsageImpl stub invocation"); @@ -50,6 +51,44 @@ jlong committed = 1L<<20; jlong max = 1L<<22; + jclass memoryPoolMXBeanClazz =jenv->FindClass( + "org/apache/harmony/lang/management/MemoryPoolMXBean"); + if (jenv->ExceptionCheck()) {return NULL;}; + + jmethodID getNameMethod = jenv->GetMethodID( + memoryPoolMXBeanClazz, + "getName", + "()Ljava/lang/String;"); + if (jenv->ExceptionCheck()) {return NULL;}; + + jobject jname = jenv->CallObjectMethod(this_been, getNameMethod); + if (jenv->ExceptionCheck()) {return NULL;}; + + jobject npname = jenv->NewStringUTF(NATIVE_POOL_NAME); + if (jenv->ExceptionCheck()) {return NULL;}; + + jclass javaLangStringClazz =jenv->FindClass( + "java/lang/String"); + if (jenv->ExceptionCheck()) {return NULL;}; + + jmethodID compareToMethod = jenv->GetMethodID( + javaLangStringClazz, + "compareTo", + "(Ljava/lang/String;)I"); + if (jenv->ExceptionCheck()) {return NULL;}; + + jint is_native = jenv->CallIntMethod(jname, compareToMethod, npname); + if (jenv->ExceptionCheck()) {return NULL;}; + + if (is_native==0) { +#ifdef _MEMMGR + init = port_mem_used_size(); + used = port_mem_committed_size() - port_mem_reserved_size(); + committed = port_mem_committed_size(); + max = port_mem_max_size(); +#endif + } + jclass memoryUsageClazz =jenv->FindClass("java/lang/management/MemoryUsage"); if (jenv->ExceptionCheck()) return NULL; jmethodID memoryUsageClazzConstructor = jenv->GetMethodID(memoryUsageClazz, "", "(JJJJ)V"); Index: working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryManagerMXBeanImpl.cpp =================================================================== --- working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryManagerMXBeanImpl.cpp (revision 644245) +++ working_vm/vm/vmcore/src/kernel_classes/native/org_apache_harmony_lang_management_MemoryManagerMXBeanImpl.cpp (working copy) @@ -30,6 +30,7 @@ #include "org_apache_harmony_lang_management_MemoryManagerMXBeanImpl.h" #include #include "environment.h" +#include "port_malloc.h" /* Native methods */ @@ -48,13 +49,14 @@ jclass memoryManagerMXBeanImplClazz =jenv->FindClass( "org/apache/harmony/lang/management/MemoryManagerMXBeanImpl"); if (jenv->ExceptionCheck()) {return;}; + jmethodID createMemoryPoolHelperMethod = jenv->GetMethodID( memoryManagerMXBeanImplClazz, "createMemoryPoolHelper", "(Ljava/lang/String;ZILorg/apache/harmony/lang/management/MemoryMXBeanImpl;)V"); if (jenv->ExceptionCheck()) {return;}; - jobject nameMP = jenv->NewStringUTF("Memory Pool #1"); + jobject nameMP = jenv->NewStringUTF(NATIVE_POOL_NAME); if (jenv->ExceptionCheck()) {return;}; jenv->CallVoidMethod(obj, createMemoryPoolHelperMethod, nameMP, JNI_TRUE, 1, memBean); Index: working_vm/make/vm/port.xml =================================================================== --- working_vm/make/vm/port.xml (revision 644245) +++ working_vm/make/vm/port.xml (working copy) @@ -62,6 +62,7 @@ + Index: working_vm/make/vm/port_ch.xml =================================================================== --- working_vm/make/vm/port_ch.xml (revision 644245) +++ working_vm/make/vm/port_ch.xml (working copy) @@ -95,6 +95,7 @@ +