일반적인 응용 프로그램이 디스크를 무슨 실린더 번호 x, 트랙 y, 섹터 z 같은 형태로 무식하게 접근하는 경우는 거의 없다. 그런 방식은 오늘날의 운영체제에서는 더욱 금기시되고 있다.
- 저희 연구실 차기 연구분야랑 어느정도 관련이 있는 이야기인데요. 요즘 SSD로 저장장치의 대세가 넘어가면서 오히려 반대로 돌아가려는 움직임이 있습니다.
낸드플래시 특성상 쓰기는 페이지 단위, 지우기는 블록 단위로 일어나기 때문에 논리적 주소가 같더라도 메모리 상의 다른 위치에 쓰이게 되죠. 이 때 논리 주소와 실제 물리 주소 사이를 연결하는 테이블을 관리하는 소프트웨어가 FTL입니다...만, SSD 펌웨어 내부에서 동작하는 FTL 입장에서는 자기가 저장하는 데이터가 어떤 데이터인지 모르기 때문에 최적의 위치에 넣는다고 넣겠지만 실제 최적의 활용과는 거리가 있죠.
그래서 요즘은 Software-defined flash라고 해서, 플래시메모리의 구조(채널 수라던지, 블록 사이즈라던지)를 운영체계에 오픈해 두고, 데이터베이스나 키밸류 스토어 응용프로그램에서 저장할 데이터의 특성 등을 고려하여서 가장 잘 들어맞는 위치에 저장할 수 있도록 하는 방법이 쓰이고 있습니다. 주로 데이터센터나 클라우드 서버처럼 높은 I/O 성능이 필요한 곳에서 사용하죠.
후자는 예전에 이 블로그 포스트에서도 본 적이 있지만, RAII 패턴과 Move sementic을 언어 차원에서 강제하는 것이 Rust죠. 가비지 컬렉터 없이 메모리 문제를 해결한 (현재로서는) 유일한 솔루션이 아닌가 합니다. 물론 프로그래머가 작정하고 타입 시스템의 빈틈을 노리고 악용한다면 답이 없겠지만요.
그리고 제 기억엔 C#에는 소멸자와 비슷한 역할을 하는 IDisposable이라는 인터페이스가 있습니다. 파일 핸들 같은 걸 가지고 있는 객체는 이 인터페이스를 상속해서 Dispose 메서드를 재정의하면 자원 해제를 제어할 수 있죠. 자바는 아마 그런 장치는 없고 수동으로 예외 처리를 해야 했던 걸로 기억합니다.
자바7부터는 try-with-resources 구문이 있어서 try(AClass a = new AClass()) {} 하면 블록이 끝날 때 a.close()가 호출됩니다. AClass는 AutoCloseable이라는 인터페이스를 구현해야 하고요. C#에서 IDisposable 구현하고 using 구문으로 묶는 것과 갈습니다.