DEV Community

RB
RB

Posted on

Custom Memory Pool: Creating memory pool for custom class

In this blog we are going to see how we can implement a string pool like cache for our own custom class.

Problem statement:
I want to create a Person class that stores name, ssn, address and email. but if i create a multiple person with the same name and ssn value, it should be considered the same person and no new object should be created in the heap. It should return the memory address of the old object. but if the combination of ssn and name is unique, it should create a new Person object in the heap.

Data Structure:
From the problem statement we can see that we need to store a key value pairs. and also the key needs to be unique representing a unique person. so we will be working with HashMap.

Concept:
We will be implementing the string pool like feature where if we find object in memory, we will return memory address of that object, else create a new object and store in the memory pool.

Implementation:

  • Setting up a Person class
public class Person{
  private String name;
  private String ssn;
  private String address;
  private String email;

  public Person(String name,String ssn,String address,String email){
    this.name = name;
    this.ssn = ssn;
    this.address = address;
    this.email = email;
 }
}
Enter fullscreen mode Exit fullscreen mode
  • we need a memory pool to store the Person objects
   private static final HashMap<String,Person> MEMORY_POOL = new HashMap<>();
Enter fullscreen mode Exit fullscreen mode

we are using static variable because all Person objects will be sharing this variable.

  • we need a method to generate unique key combination for each Person object.
private static int generateKey(String name, String ssn){
  // simple key,name combination would also work
  // but you would need to change Integer to String in hashmap
  return Objects.hash(name,ssn);
}
Enter fullscreen mode Exit fullscreen mode
  • Next we will need a method to store Person object in the memory pool.
private static void addToPool(Integer key, Person value ){
  Person.MEMORY_POOL.putIfAbsent(key,value);
}
Enter fullscreen mode Exit fullscreen mode
  • Since constructor call always initializes new object we need to call constructor conditionally, and also we do not want anyone to call constructor directly. so making constructor private and exposing static method to create Person object, this method makes a decision to either create a new object or get from the memory pool.

private Person(String name,String ssn,String address,String email){
   this.name = name;
   this.ssn = ssn;
   this.address = address;
   this.email = email;
}
public static Person createPerson(String name,String ssn,String address,String email){
  int key = Person.generateKey(name,ssn);
  if(Person.MEMORY_POOL.containsKey(key)){
    return MEMORY_POOL.get(key);
  }
  Person p = new Person(name,ssn,address,email);
  Person.addToPool(key,p);
 return p;
}

Enter fullscreen mode Exit fullscreen mode
  • Putting it all together.
import java.util.HashMap;
import java.util.Objects;

public class Person{
    private static final HashMap<Integer,Person> MEMORY_POOL =
            new HashMap<>();

    private String name;
    private String ssn;
    private String address;
    private String email;

    private Person(String name,String ssn,String address,String email){
        this.name = name;
        this.ssn = ssn;
        this.address = address;
        this.email = email;
    }

    private static int generateKey(String name, String ssn){
        return Objects.hash(name,ssn);
    }

    private static void addToPool(Integer key, Person value ){
        Person.MEMORY_POOL.putIfAbsent(key,value);
    }

    public static Person createPerson(String name,String ssn,String address,String email){
        int key = Person.generateKey(name,ssn);
        if(Person.MEMORY_POOL.containsKey(key)){
            return MEMORY_POOL.get(key);
        }
        Person p = new Person(name,ssn,address,email);
        Person.addToPool(key,p);
        return p;
    }

    private String getName(){
        return this.name;
    }
    public String getEmail(){
        return this.email;
    }
    public String getAddress(){
        return this.address;
    }

    public void setEmail(String email){
        this.email = email;
    }

    public void setAddress(String address){
        this.address = address;
    }

    public String toString(){
        return "Person ( name: "+ this.name + ", ssn: " + this.ssn + ", email: " + this.email + ", address: "+this.address + " )";
    }

}
Enter fullscreen mode Exit fullscreen mode
  • Testing
public class Main {

    public static void main(String[] args){
        Person p = Person.createPerson("john","234-df-44","usa", "john@usa.email.com");
        System.out.println("Person p: " + p);

        // should not create a Person object since name and ssn are same
        Person p1 = Person.createPerson("john","234-df-44","mexico", "john@mexico.email.com");
        System.out.println("Person p1: " + p1);

        Person p2 = Person.createPerson("Johnny","776-dr4-990","canada", "johnny@canada.email.com");
        System.out.println("Person p2: " + p2);

        System.out.println();
        // checking if the p and p1 reference to the same memory location
        System.out.println("p==p1: " + (p == p1)); // true
        // can also be verified with equals method since
        // we never override the method in Person class
        System.out.println("p.equals(p1): " + p.equals(p1)); // true

        // checking if p1 and p2 are equal
        System.out.println("p1==p2: " + (p1 == p2)); // false

        System.out.println();
        System.out.println("updating the email for p1 to hello@world.com");
        p1.setEmail("hello@world.com");
        System.out.println("Person p: " + p);
        System.out.println("Person p1: " + p1);
    }
}

Enter fullscreen mode Exit fullscreen mode

On running the above main method we can see the output as:

Person p: Person ( name: john, ssn: 234-df-44, email: john@usa.email.com, address: usa )
Person p1: Person ( name: john, ssn: 234-df-44, email: john@usa.email.com, address: usa )
Person p2: Person ( name: Johnny, ssn: 776-dr4-990, email: johnny@canada.email.com, address: canada )

p==p1: true
p.equals(p1): true
p1==p2: false

updating the email for p1 to hello@world.com
Person p: Person ( name: john, ssn: 234-df-44, email: hello@world.com, address: usa )
Person p1: Person ( name: john, ssn: 234-df-44, email: hello@world.com, address: usa )
Enter fullscreen mode Exit fullscreen mode

From the output we can see that p and p1 are same objects. since they have same ssn and name combination, new Person object ("john","234-df-44","mexico","john@mexico.email.com") is not created. The email update of p1 is reflected on both p1 and p object, which shows that they both point to the same object in the heap.

Top comments (0)