0022627: Change OCCT memory management defaults
[occt.git] / src / Standard / Standard.cxx
1 // File:        Standard.cxx
2 // Created:     Tue Mar 15 17:33:31 2005
3 // Author:      Peter KURNEV
4 //              <pkv@irinox>
5
6
7 #include <Standard.ixx>
8
9 #include <stdlib.h>
10
11 #include <Standard_MMgrOpt.hxx>
12 #include <Standard_MMgrRaw.hxx>
13 #include <Standard_MMgrTBBalloc.hxx>
14
15 #if(defined(_WIN32) || defined(__WIN32__))
16 #include <windows.h>
17 #include <malloc.h>
18 #endif
19
20 // Global reentrant flag
21 static Standard_Boolean Standard_IsReentrant = Standard_True;
22
23 //=======================================================================
24 //class    : Standard_MMgrFactory 
25 //purpose  : Container for pointer to memory manager;
26 //           used to construct appropriate memory manager according
27 //           to environment settings, and to ensure destruction upon exit
28 //=======================================================================
29
30 class Standard_MMgrFactory {
31  public:
32   Standard_MMgrFactory();
33   ~Standard_MMgrFactory();
34  public:
35   Standard_MMgrRoot* myFMMgr;
36 };
37
38 //=======================================================================
39 //function : Standard_MMgrFactory
40 //purpose  : Check environment variables and create appropriate memory manager
41 //=======================================================================
42
43 Standard_MMgrFactory::Standard_MMgrFactory()
44 : myFMMgr (NULL)
45 {
46   char* aVar;
47   Standard_Integer anAllocId   = (aVar = getenv ("MMGT_OPT"      )) ?  atoi (aVar)       : 0;
48   Standard_Boolean toClear     = (aVar = getenv ("MMGT_CLEAR"    )) ? (atoi (aVar) != 0) : Standard_True;
49
50
51   // on Windows (actual for XP and 2000) activate low fragmentation heap
52   // for CRT heap in order to get best performance.
53   // Environment variable MMGT_LFH can be used to switch off this action (if set to 0)
54 #if defined(_MSC_VER)
55   aVar = getenv ("MMGT_LFH");
56   if ( aVar == NULL || atoi (aVar) != 0 )
57   {
58     ULONG aHeapInfo = 2;
59     HANDLE aCRTHeap = (HANDLE)_get_heap_handle();
60     HeapSetInformation (aCRTHeap, HeapCompatibilityInformation, &aHeapInfo, sizeof(aHeapInfo));
61   }
62 #endif
63
64   aVar = getenv ("MMGT_REENTRANT");
65   if ( aVar != NULL ) 
66     Standard_IsReentrant = (atoi (aVar) != 0);
67
68   switch (anAllocId)
69   {
70     case 1:  // OCCT optimized memory allocator
71     {
72       Standard_Boolean bMMap       = (aVar = getenv ("MMGT_MMAP"     )) ? (atoi (aVar) != 0) : Standard_True;
73       Standard_Integer aCellSize   = (aVar = getenv ("MMGT_CELLSIZE" )) ?  atoi (aVar) : 200;
74       Standard_Integer aNbPages    = (aVar = getenv ("MMGT_NBPAGES"  )) ?  atoi (aVar) : 1000;
75       Standard_Integer aThreshold  = (aVar = getenv ("MMGT_THRESHOLD")) ?  atoi (aVar) : 40000;
76       myFMMgr = new Standard_MMgrOpt (toClear, bMMap, aCellSize, aNbPages, aThreshold, Standard_IsReentrant);
77       break;
78     }
79     case 2:  // TBB memory allocator
80       myFMMgr = new Standard_MMgrTBBalloc (toClear);
81       break;
82     case 0:
83     default: // system default memory allocator
84       myFMMgr = new Standard_MMgrRaw (toClear);
85   }
86 }
87
88 //=======================================================================
89 //function : ~Standard_MMgrFactory
90 //purpose  : 
91 //=======================================================================
92
93 Standard_MMgrFactory::~Standard_MMgrFactory()
94 {
95   if ( ! myFMMgr ) {
96     myFMMgr->Purge(Standard_True);
97 //  delete myFMMgr;
98 //  myFMMgr = 0;  
99   }
100 }
101
102 //=======================================================================
103 // function: GetMMgr
104 //
105 // This static function has a purpose to wrap static holder for memory 
106 // manager instance. 
107 //
108 // Wrapping holder inside a function is needed to ensure that it will
109 // be initialized not later than the first call to memory manager (that
110 // would be impossible to guarantee if holder was static variable on 
111 // global or file scope, because memory manager may be called from 
112 // constructors of other static objects).
113 //
114 // Note that at the same time we could not guarantee that the holder 
115 // object is destroyed after last call to memory manager, since that 
116 // last call may be from static Handle() object which has been initialized
117 // dynamically during program execution rather than in its constructor.
118 //
119 // Therefore holder currently does not call destructor of the memory manager 
120 // but only its method Purge() with Standard_True.
121 //
122 // To free the memory completely, we probably could use compiler-specific 
123 // pragmas (such as '#pragma fini' on SUN Solaris and '#pragma init_seg' on 
124 // WNT MSVC++) to put destructing function in code segment that is called
125 // after destructors of other (even static) objects. However, this is not 
126 // done by the moment since it is compiler-dependent and there is no guarantee 
127 // thatsome other object calling memory manager is not placed also in that segment...
128 //
129 // Note that C runtime function atexit() could not help in this problem 
130 // since its behaviour is the same as for destructors of static objects 
131 // (see ISO 14882:1998 "Programming languages -- C++" 3.6.3)
132 //
133 // The correct approach to deal with the problem would be to have memory manager 
134 // to properly control its memory allocation and caching free blocks so 
135 // as to release all memory as soon as it is returned to it, and probably
136 // even delete itself if all memory it manages has been released and 
137 // last call to method Purge() was with True.
138 //
139 // Note that one possible method to control memory allocations could
140 // be counting calls to Allocate() and Free()...
141 //
142 //=======================================================================
143
144 static Standard_MMgrRoot* GetMMgr()
145 {
146   static Standard_MMgrFactory aFactory;
147   return aFactory.myFMMgr;
148 }
149
150 //=======================================================================
151 //function : Allocate
152 //purpose  : 
153 //=======================================================================
154
155 Standard_Address Standard::Allocate(const Standard_Size size)
156 {
157   return GetMMgr()->Allocate(size);
158 }
159
160 //=======================================================================
161 //function : Free
162 //purpose  : 
163 //=======================================================================
164
165 void Standard::Free(Standard_Address& aStorage)
166 {
167   GetMMgr()->Free(aStorage);
168 }
169
170 //=======================================================================
171 //function : Reallocate
172 //purpose  : 
173 //=======================================================================
174
175 Standard_Address Standard::Reallocate(Standard_Address& aStorage,
176                                       const Standard_Size newSize)
177 {
178   return GetMMgr()->Reallocate(aStorage, newSize);
179 }
180
181 //=======================================================================
182 //function : Purge
183 //purpose  : 
184 //=======================================================================
185
186 Standard_Integer Standard::Purge()
187 {
188   return GetMMgr()->Purge();
189 }
190
191 //=======================================================================
192 //function : IsReentrant
193 //purpose  : 
194 //=======================================================================
195
196 Standard_Boolean Standard::IsReentrant()
197 {
198   return Standard_IsReentrant;
199 }
200
201 //=======================================================================
202 //function : SetReentrant
203 //purpose  : 
204 //=======================================================================
205
206 void Standard::SetReentrant (const Standard_Boolean isReentrant)
207 {
208   Standard_IsReentrant = isReentrant;
209   GetMMgr()->SetReentrant (isReentrant);
210 }