1. Field of the Invention
This invention relates to computer systems, and more particularly, to managing objects in a computing system.
2. Description of the Relevant Art
The performance of computer systems is dependent on both hardware and software. As those skilled in the art know, program code is typically written in a source language which is subsequently compiled into object code for execution on a given machine. In some cases, compilation to a final object code format may take place well in advance of its execution. For example, program source code may be compiled to object code which is stored on a computer readable storage medium (e.g., a computer readable disk, flash drive, or other media). This medium may then sold by a software vendor to numerous customers who then install the object code on their computing systems where it may be accessed for execution. In some cases, such code may be conveyed via network communication, or otherwise as is increasingly common. In other cases, source code is translated to an intermediate code type (such as bytecode) which is conveyed to others for execution. In these cases, the target machine may itself have a virtual machine or other components configured to translate the intermediate code representation to an object code for execution by the particular machine.
Whichever paradigm is utilized for compiling source code, as the resulting compiled code is generally intended for execution on a particular type of machine (e.g., a machine utilizing a particular microprocessor architecture, or family of architectures), this code must generally adhere to particular requirement of the target machine. Generally speaking, processors and processor types have addressing mechanisms which are designed to access and manage data in a particular way. For example, processors are not generally designed to address and access data in arbitrary sized units. Rather, processors are generally designed or optimized to address and access data in what are referred to as “word” sized units. While variations exist, common word sizes are 32 bits and 64 bits. Therefore, a processor with a word size of 32 bits may address data as 32 bit (or 4 byte size) units. The consequence of such a design is that if such a processor attempts to access data on other than a 32 bit byte boundary, an access violation or fault may occur.
Given the above considerations, compilers generally have data alignment requirements. Because of such requirements, more memory than needed may be allocated for storage of particular data. For example, program code may include a variable used to represent one of two state (e.g., a flag of some type). As it is only necessary to represent one of two possible states, a single bit would suffice for representation of the state. However, due to program code alignment considerations, a full word sized amount of memory may be allocated for storage of this single bit. In other words, a full eight bytes of storage could be allocated for storage of such a variable. In database and other systems where large numbers of data objects may be used, this additional storage used may be multiplied many thousand, millions, or billions, of times. Consequently, the storage overhead due to the above discussed alignment requirements may become significant.
In view of the above, efficient methods and mechanisms for managing objects, and memory utilization, in a computing system are desired.
Systems and methods for managing objects in a computing system are contemplated.
Embodiments of a method are contemplated in which an object in a computing system may be in one of multiple states. Typically, the state of such an object may be represented within the object—for example, using a state identifier (state ID). However, in various embodiments, a method is contemplated that does not use an explicit representation of an object's state. Rather, the method includes representing the state of an object by its type. Accordingly, multiple distinct types are used to represent the state of an object. Should a change in state of an object be desired, then the object's type is changed from a first type to a second (different) type. In various embodiments, each distinct type corresponds to a different class in an object oriented system. Objects in such a system represent instances of these classes. By detecting an objects type, whether explicitly or implicitly, the objects state may be determined.
In order to change an object from one type to another, embodiments are contemplated in which a new object is created to represent the object in the new state. In order to avoid memory allocation overhead, the method may perform object creation using an operation which does not invoke or cause memory allocation. Such methods may take an identification of a memory location of the current object and use it as if it had been allocated for the new object. Data initialization of the new object, at this existing memory location, is then performed. In various embodiments, a change in the data content of the object may not be desired. Therefore, initialization of the new object may expressly avoid initialization of the preexisting data members. In some embodiments, each object includes a pointer to a table for use in accessing methods and functions of the object. In such cases, initialization of a new object may include changing this pointer to identify a new table that corresponds to the new type.
These and other embodiments are described herein and will be more fully appreciated upon reference to the following description and drawings.
While the invention is susceptible to various modifications and alternative forms, specific embodiments are shown by way of example in the drawings and are herein described in detail. It should be understood, however, that drawings and detailed description thereto are not intended to limit the invention to the particular form disclosed, but on the contrary, the invention is to cover all modifications, equivalents and alternatives falling within the spirit and scope of the present invention as defined by the appended claims.
In the following description, numerous specific details are set forth to provide a thorough understanding of the present invention. However, one having ordinary skill in the art should recognize that the invention may be practiced without these specific details. In some instances, circuits, structures, and techniques have not been shown in detail to avoid obscuring the present invention.
Turning now to
Generally speaking, a Boolean type data member may require only a single bit to represent its value (e.g., “1” for True, and “0” for false). Integer and floating point data types may (depending on the implementation) be represented by a 4 byte value, and a character by a single byte value. Assuming these to be how the data members are represented, then the data members shown in pseudocode 100 may be represented by a total of 1 bit (bool)+4 bytes (int)+1 byte (char)+4 bytes (int)+1 bit (bool)+4 bytes (float)=106 bits. If in a given embodiment there are 500K objects 110 instantiated which are based on this class, then this data may be represented by roughly 6½ megabytes (MB) of storage (500K×106 bits). However, due to data alignment requirements, the actual storage used to store this data may be significantly greater.
For example, in
Even in cases where seemingly little additional data is required in a particular object, data alignment and memory allocation techniques may result in significant overhead.
In the example shown, data_value is of the union type and may be one of a Boolean, integer, floating point, or double precision data type. Such an approach may, for example, be used when it is known that data_value may be any of, but only one of, these data types within a given object. In this manner, a common (base) object type may be used for representation of a number of object types which could be storing a data_value of different types. While there are many reasons a given object may be associated with more than a single state, it is often desirable or necessary to know the current state of an object in order to determine which operations are suitable for the given object. Therefore, a state_ID such as that in pseudocode 300 may be included to identify the current state of an object. Also shown in the pseudocode 300 is an illustration that the current state may affect which of multiple methods may be used. For example, if the current state is “0”, then method1( ) may be called; otherwise, method2( ) may be called.
In
It is noted that there is typically metadata that is also stored as part of an object (such metadata has not been included in the storage requirements discussed above). In the example of
Turning now to
As those skilled in the art will appreciate, permitting an inheriting class to override the functionality of base class method is an important aspect of polymorphism in object oriented programming. In the present example, the implementation shown resembles that of the C++ programming language to declare methods virtual and override them in a subclass. However, it is noted that other implementations and programming language paradigms for implementing polymorphism and related concepts are possible and are contemplated.
Also shown in
While an approach such as that depicted in
Creation of a new object also generally entails initialization of the object once it is created. For example, various data members of the object may be initialized to particular values, metadata such as virtual method table pointers may be established, and so on. Taking
. . . new data_types—3C
As data_types—3C includes a virtual method (method1), a portion of how it is laid out in memory may resemble that of object 520 in
If a state change for the object is detected (conditional block 614), then a state change is performed. It is noted that while block 614 is shown to follow block 606, then need not be the case. The diagram of
For example, if a given object is currently in a state “C” (e.g., data_types—3C) and the object's state is changed to a state “A” (e.g., data_types—3A), then in one embodiment a placement new operator may be used to change the state of the object from state C to state A. As we do not desire the object to really change—only its state—this may effectively be accomplished as follows:
In the above code, the process of memory allocation is not performed. Rather, the operator “new” assumes the memory has already been allocated and is at the location pointed to by object1 (block 616, 618). The constructor for data types 3A is then called to initialize the object at location object 1. However, as we don't wish to change the data members of the object (we merely want to change the object's state), the method used must seek to avoid making any changes to the object's data. In one embodiment, the constructor called as part of the above state change is particularly designed to leave the values of the data members unchanged (block 620). However, this constructor is configured to change the virtual table pointer (block 622) of the object. Changing this table pointer may be viewed as an implicit representation of the state of the entire object. In other words, while the state of the object is not explicitly included in the object, the table pointer may be used as a type of encoding of the state of the object. Therefore, we have effectively changed the state of the object by modifying the existing object to be an object with a different type (without performing the memory allocation process) at the identical location of the object in its prior state, and we have left the data members undisturbed. To this extent the object may (for the most part) look identical before and after the state change. However, a change in the virtual table pointer effectively causes a change in type due to each class having its own virtual method table. Accordingly, a call to method1 will call the method corresponding to data_type—3A instead of data_type—3C. Note that when making a call to method1 there is no explicit check as to the type or state of the object making the call. Rather, the correct method is automatically called due to the virtual method table pointer having been changed. In this manner, a change in state of the object has been accomplished by changing its type—without allocating new memory or copying data members from the previous object type to the new object type.
Following the procedure described in
Turning now to
Having defined the base and subclasses, a new object(s) may be created (block 806). This new object may be created in either the first state or the second state. For example, if it desired that the object be in the first state then an object of the base class type may be created. Alternatively, if it is desired that the object be in the second state then an object of the subclass type may be created. If then a method call by an object to set its state is detected (conditional block 808), a determination may be made as to whether the object is already in the desired state (conditional block 810). For example, if an object in the first state calls a method to set the object to the first state, then the method call may (effectively) do nothing as the object is already in the desired state. Alternatively, if the object is not already in the desired state, then the method call may cause a change in state as described above (e.g., as described in
class NonGlobalType:public BaseClass
In addition, class NonGlobalType declares the following two virtual methods:
The first method, GetIsGlobal, is configured to check whether the calling object is of the GlobalType. As this method is part of the NonGlobalType class, it returns a value of false (i.e., the object is not of the type GetIsGlobal). In addition, a method SetIsGlobal is defined which is configured to take a Boolean value parameter. If the parameter evaluates to true, then an attempt is made to make the calling object an object of type GlobalType. In addition to the above, a destructor (˜NonGlobalType( )) is declared. Finally, two constructors are declared, one which takes a parameter and one which does not. As will be described shortly, these two distinguishable constructors are created so that we may control how an object is initialized when created. These declaration are as follows:
In addition to the above, the code 900 in
class GlobalType:public NonGlobalType
As in the parent class, two virtual methods are declared. The first method, GetIsGlobal, overrides the parent class method and is also configured to check whether the calling object is of the GlobalType. However, in this case, as this method is part of the GlobalType class it returns a value of true (i.e., the object is of the type GetIsGlobal). In addition, a method SetIsGlobal is defined which is configured to take a Boolean value parameter. If the parameter evaluates to true, then an attempt is made to make the calling object an object of type GlobalType.
In addition to the above, a destructor (˜GlobalType( )) is declared. Finally, two constructors are declared, one which takes a parameter and one which does not. As in the base class, two distinguishable constructors are created so that we may control how an object is initialized when created. These declaration are as follows:
Also shown in
In the body of the above method, a placement new operation is conditionally called in dependence on whether the parameter “value” evaluates to true or not. If “value” evaluates to true (e.g., we wish to change the state of the object to the type
GlobalType), then a new operation is called with the “this” pointer as a parameter. In one embodiment, the “this” pointer corresponds to the calling object which is of type NonGlobalType and identifies where in memory this object is located.
As this is a placement new type of operation, a memory allocation procedure is not performed. However, a call to the constructor of the class for the other type (i.e., not the constructor for the existing type of object of corresponding to the this pointer, but the constructor for the GlobalType) is made. If a call to the default constructor were made, then whatever initializations performed by the default constructor would be performed, including a change to the virtual method table pointer. However, as we do not desire any changes to the data members of the object (we merely want to change its state), an alternative distinguishable constructor has been defined and is called in this case. Here a parameterized constructor (GlobalType(_FALSE)) is called to distinguish it from the default constructor.
In this context, a parameterized method simply means that the constructor includes a parameter in the call which permits us to distinguish it from the default constructor which does not include a parameter. In various embodiments, this parameterized constructor is expressly configured to not change the data members. As we may have other data members or actions we wish performed at initial creation of an object, we may use this separate constructor for this purpose of avoiding changes to the data members. If in the above example, a call is made to SetIsGlobal by an object of the type NonGlobalType, and the parameter “value” evaluates to false (i.e., we do not wish the object to be of the type GlobalType), then the clause following the if expression is not executed. In the embodiment shown, when the expression evaluates to false, the method simply returns without performing a state change operation as the object is already not an object of the GlobalType.
Code 900 in
In contrast to the method of the class NonGlobalType, this method checks whether the parameter “value” evaluates to false. Therefore, if an object of type GlobalType calls the method SetIsGlobal with a parameter of false, the conditional if expression will evaluate to true and perform the following clause. In other words, if the object is of type GlobalType and a call is made to SetIsGlobal with parameter set to false (i.e., we do not want the object to be of the GlobalType), then a change in state is performed by the following placement new operation and constructor call of the class of the other type (NonGlobalType). As in the previous case, a special parameterized constructor may be created which is expressly configured to leave the data members unchanged.
Finally, code 900 in
NonGlobalType::NonGlobalType(Boolean b):BaseClass(b) { }
The following constructor code for the GlobalType class calls the constructor for the class NonGlobalType.
GlobalType::GlobalType(Boolean b):NonGlobalType(b) { }
However, as noted above, the call to the constructor GlobalType calls the constructor BaseClass. Therefore, in each case the constructor causes the actions of its parent class constructor to be executed. However in various embodiments none of the constructors down to the least derived class perform any actions so no code is generated. In various embodiments, as discussed above, the constructor BaseClass(b) is expressly defined so as not to change the data members of the object. While these constructors discussed above result in a call to the same constructor, other embodiments could have the constructor defined within the class itself and have it designed to leave the data member values unchanged. Numerous such alternative embodiments are possible and are contemplated. It is noted that while the above description discusses virtual methods which enable automatically calling the correct method for a given object, other embodiments could use alternative approaches. For example, in other embodiments type checking could be explicitly performed at runtime (e.g., using run time type information, RTTI, or some other approach). Using such a type checking mechanism, an appropriate method for a given object (type) could be called. In this manner, one could also avoid explicitly providing a state identifier within the object. Various such alternative embodiments are possible and are contemplated.
Referring to
Generally speaking, source code 1022 is written by a software developer, stored in memory 1040 within platform 1050, and may be compiled by a compiler 1030. This compiler 1030 may produce compiled object code 1024, which may be conveyed to a customer to execute on platform 1052. As previously discussed, in some cases the code produced by a compiler corresponds to an intermediate representation (which may generally be referred to as object code herein) which then undergoes further translation, interpretation, and/or compilation on a target machine. In the embodiment shown, copies of object code 1024 on platforms 1050 and 1052 are shown to illustrate the production of object code 1024 on platform 1050 and the execution of object code 1024 on platform 1052.
Platform 1050 may have one or more processors 1002, although only one is shown. Each processor 1002 may, for example, include a superscalar microarchitecture with one or more multi-stage pipelines. Alternatively, each processor may correspond to a virtual machine operable to interpret or otherwise execute program instructions. Each processor 1002 may be configured to execute instructions of software applications corresponding to an instruction set architecture (ISA) such as x86, SPARC®, PowerPC®, MIPS®, ARM®, or otherwise. Also, each processor 1002 may be designed to execute multiple strands, or threads. For example, a multi-thread software application may have each of its software threads scheduled to be executed on a separate pipeline within a processor 1002, or alternatively, a pipeline may process multiple threads via control at certain function units.
Each processor 1002 may comprise a first-level cache or in other embodiments, the first-level cache may be outside the processor 1002. Each processor 1002 and first-level cache may be coupled to shared resources such as a second-level caches and lower-level memory 1040 via memory controllers 1092. Interfaces between the different levels of caches may comprise any suitable technology. In other embodiments, other levels of caches may be present between a first-level cache and memory controller 1092. In one embodiment, an I/O interface may be implemented in memory controller 1092 to provide an interface for I/O devices to cache 1090, other caches located both internally and externally to processor 1002, and to processor 1002. Memory controllers 1092 may be coupled to lower-level memory, which may include other levels of cache on the die outside the microprocessor, dynamic random access memory (DRAM), dual in-line memory modules (dimms) in order to bank the DRAM, a hard disk, or a combination of these alternatives.
Generally speaking, compiler 1030 is used to produce object code 1024 from source code 1022. The source code 1022 stored in memory 1040 may be software applications written by a software developer in a high-level language such as C, C++, Fortran, or otherwise. The source code 1022 may be written to perform predetermined steps of an algorithm or method. One or more libraries may be used during the software development. These libraries, which may be written by the software developer, may include code and data that describe one or more subroutine definitions. These subroutines may be referenced for use by code in other files such as through a function call. The libraries may allow the sharing and changing of code and data in a modular fashion. The libraries may utilize references known as links to connect to executable files. A link-editor and a runtime linker (not shown), both used in later stages, may typically perform the process of linking
In various embodiments, the compiler 1030 may be configured to determine that particular application code may benefit from the methods and mechanisms described herein. In such a case, the compiler 1030 may automatically generate the additional code needed and perform suitable modifications to the code to perform the methods and mechanism. In this manner, the methods and mechanisms described herein may represent possible optimizations that may be performed by a compiler.
Various embodiments of the methods and mechanisms described herein may further include receiving, sending or storing instructions and/or data implemented in accordance with the above description upon a computer-accessible medium. Generally speaking, a computer-accessible medium may include storage media or memory media such as magnetic or optical media, e.g., disk or DVD/CD-ROM, volatile or non-volatile media such as RAM (e.g. SDRAM, DDR, RDRAM, SRAM, etc.), ROM, etc.
Although the embodiments above have been described in considerable detail, numerous variations and modifications will become apparent to those skilled in the art once the above disclosure is fully appreciated. It is intended that the following claims be interpreted to embrace all such variations and modifications.