Buffer Cache
Postgresql uses OS calls which make use of OS level disk caching. It does NOT use direct access to disks like Oracle does (except in some cases with writing the WAL logs which can be adjusted via the wal_sync_method parameter). The Postgresql database cache uses the clock-sweep algorithm which is similar to Oracle’s touch count algorithm where basically the more frequently a page is referenced the less likely it is to be evicted. I believe most operating systems use some sort of LRU algorithm which is suitable to typical OS usage.
Having a dedicated buffer cache for the database makes a lot of sense as it can use algorithms designed to maximise database performance. For example,it knows that scanning entire tables into the cache might not always be a good idea as it can trash existing more popular data buffers.
However since the OS also keeps its own cache of disk blocks,there will often be redundant data stored in memory. For this reason,it is generally recommended not to give Postgresql more than about 25% to 30% of the total RAM for its shared buffer. One popular recommendation is that using more than about 8GB for shared buffers starts to hit scalability issues,but I have one specialised server with 32GB shared_buffer and 8GB effective_cache_size which works very well. So a compromise is required between giving the database more memory and reducing the wastage caused by redundantly storing the same data in two separate caches. This can be initially confusing to Oracle DBA’s who are used to giving the database every available scrap of memory to do with as it pleases.