-
Notifications
You must be signed in to change notification settings - Fork 0
Perf : LOH 최적화 #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Perf : LOH 최적화 #21
Changes from 7 commits
e032d5e
ace9e1a
d4f8631
e50c079
81dae08
ca62d4d
42eb294
0eaa3d8
369297e
044083c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||||||||||||||||||||||||||||||
| using System.Text.Json.Serialization; | ||||||||||||||||||||||||||||||||||
| using System.Buffers; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| namespace ProjectVG.Infrastructure.Integrations.TextToSpeechClient.Models | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
|
|
@@ -17,11 +18,23 @@ public class TextToSpeechResponse | |||||||||||||||||||||||||||||||||
| public string? ErrorMessage { get; set; } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||
| /// 오디오 데이터 (바이트 배열) | ||||||||||||||||||||||||||||||||||
| /// 오디오 데이터 (바이트 배열) - 레거시 호환성용 | ||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||
| [JsonIgnore] | ||||||||||||||||||||||||||||||||||
| public byte[]? AudioData { get; set; } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||
| /// ArrayPool 기반 오디오 메모리 소유자 (LOH 방지) | ||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||
| [JsonIgnore] | ||||||||||||||||||||||||||||||||||
| public IMemoryOwner<byte>? AudioMemoryOwner { get; set; } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||
| /// 실제 오디오 데이터 크기 | ||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||
| [JsonIgnore] | ||||||||||||||||||||||||||||||||||
| public int AudioDataSize { get; set; } | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion IMemoryOwner 소유권 명시 필요 (잠재적 누수/이중 해제 예방 가이드 추가 권장) 응답 DTO가 IMemoryOwner를 public으로 노출하므로 소유권/수명 규약을 문서화하거나 안전한 전달 API를 제공하는 편이 좋습니다. 예: 소비자가 세그먼트에 붙이지 않고 버릴 때 직접 해제해야 함을 명시하거나, 응답에서 “소유권 가져가기” 메서드를 제공해 중복 해제를 방지하세요. 아래 보조 메서드 추가를 제안드립니다(응답 → 세그먼트로 안전 이전): // 클래스 내부에 추가
public bool TryTakeAudioOwner(out IMemoryOwner<byte>? owner, out int size)
{
owner = AudioMemoryOwner;
size = AudioDataSize;
AudioMemoryOwner = null;
AudioDataSize = 0;
return owner != null;
}🤖 Prompt for AI Agents
Comment on lines
+33
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion IMemoryOwner/크기 세터 접근 축소로 오·남용 방지 소비자가 임의로 교체하면 이중 Dispose/누수 가능성이 있습니다. 동일 어셈블리에서만 설정되도록 setter를 internal로 축소하세요. - public IMemoryOwner<byte>? AudioMemoryOwner { get; set; }
+ public IMemoryOwner<byte>? AudioMemoryOwner { get; internal set; }
- public int AudioDataSize { get; set; }
+ public int AudioDataSize { get; internal set; }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||
| /// 오디오 길이 (초) | ||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -82,7 +82,104 @@ public void ChatSegment_MemoryOwner_vs_ByteArray_Test() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(segment1.GetAudioSpan().ToArray(), segment2.GetAudioSpan().ToArray()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine($"기존 방식 - HasAudio: {segment1.HasAudio}, 데이터 크기: {segment1.AudioData?.Length ?? 0}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine($"최적화 방식 - HasAudio: {segment2.HasAudio}, 데이터 크기: {segment2.AudioDataSize}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine($"최적화 방식 - HasAudio: {segment2.HasAudio}, 데이터 크기: {segment2.GetAudioSpan().Length}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void ChatSegment_GetAudioSpan_SafetyBoundaryTest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 경계 조건 테스트: 유효한 범위 내에서의 메모리 접근 안전성 검증 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var testData = GenerateTestAudioData(1000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var memoryOwner = MemoryPool<byte>.Shared.Rent(500); // 더 작은 메모리 할당 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var actualMemorySize = memoryOwner.Memory.Length; // 실제 할당된 메모리 크기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var copySize = Math.Min(500, actualMemorySize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| testData.AsSpan(0, copySize).CopyTo(memoryOwner.Memory.Span); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 유효한 크기로 설정 (실제 메모리 크기 이하) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var validSize = actualMemorySize - 10; // 안전한 크기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var segment = ChatSegment.CreateText("Test content") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .WithAudioMemory(memoryOwner, validSize, "audio/wav", 5.0f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // GetAudioSpan이 정확한 크기를 반환해야 함 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var span = segment.GetAudioSpan(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 요청한 크기만큼 반환되어야 함 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(validSize, span.Length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine($"요청 크기: {validSize}, 실제 메모리: {actualMemorySize}, 반환된 span 크기: {span.Length}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+91
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chain소유권 이전 규약 위반: WithAudioMemory 사용 시 memoryOwner를 using으로 해제하면 이중 Dispose 위험 WithAudioMemory는 소유권을 ChatSegment로 이전합니다. 현재 적용 예(요지: using 제거, segment.Dispose()만 호출): -using var memoryOwner = MemoryPool<byte>.Shared.Rent(500); // 더 작은 메모리 할당
+var memoryOwner = MemoryPool<byte>.Shared.Rent(500); // 소유권은 ChatSegment로 이전됨
...
-var segment = ChatSegment.CreateText("Test content")
- .WithAudioMemory(memoryOwner, validSize, "audio/wav", 5.0f);
+var segment = ChatSegment.CreateText("Test content")
+ .WithAudioMemory(memoryOwner, validSize, "audio/wav", 5.0f);
+try
+{
+ var span = segment.GetAudioSpan();
+ Assert.Equal(validSize, span.Length);
+}
+finally
+{
+ segment.Dispose();
+}레포 전역에서 동일 패턴을 점검하려면 다음을 실행해주세요: 🏁 Script executed: #!/bin/bash
# WithAudioMemory 사용 주변의 using var memoryOwner 패턴 탐지
rg -nP -C3 $'using\\s+var\\s+\\w+\\s*=\\s*MemoryPool<byte>\\.Shared\\.Rent\\(.+\\)|\\.WithAudioMemory\\(' --type csLength of output: 9773 소유권 이전 규약 위반 — WithAudioMemory에 IMemoryOwner 전달 시 memoryOwner를 using으로 해제하면 이중 Dispose(오류) 발생 위험 WithAudioMemory가 메모리 소유권을 ChatSegment로 이전한다고 가정하면, 현재 테스트들이 MemoryPool에서 Rent한 IMemoryOwner를 수정 방안(예): memoryOwner를 using으로 해제하지 말고 ChatSegment가 소유권을 해제하도록 segment.Dispose()를 호출(또는 ChatSegment를 using으로 감싸 자동 Dispose). 예전 제안된 변경(diff)은 유효합니다: -using var memoryOwner = MemoryPool<byte>.Shared.Rent(500); // 더 작은 메모리 할당
+var memoryOwner = MemoryPool<byte>.Shared.Rent(500); // 소유권은 ChatSegment로 이전됨
...
-var segment = ChatSegment.CreateText("Test content")
- .WithAudioMemory(memoryOwner, validSize, "audio/wav", 5.0f);
+var segment = ChatSegment.CreateText("Test content")
+ .WithAudioMemory(memoryOwner, validSize, "audio/wav", 5.0f);
+try
+{
+ var span = segment.GetAudioSpan();
+ Assert.Equal(validSize, span.Length);
+}
+finally
+{
+ segment.Dispose();
+}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void ChatSegment_GetAudioSpan_EmptyAndNullSafetyTest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // null AudioMemoryOwner는 이제 예외가 발생해야 함 (ArgumentNullException) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var nullException = Assert.Throws<ArgumentNullException>(() => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ChatSegment.CreateText("Test").WithAudioMemory(null!, 100, "audio/wav", 1.0f)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal("audioMemoryOwner", nullException.ParamName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // AudioDataSize가 0인 경우는 여전히 정상 작동해야 함 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var memoryOwner = MemoryPool<byte>.Shared.Rent(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var segment2 = ChatSegment.CreateText("Test").WithAudioMemory(memoryOwner, 0, "audio/wav", 1.0f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var span2 = segment2.GetAudioSpan(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.True(span2.IsEmpty); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 기존 AudioData 방식 (null 허용) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var segment3 = ChatSegment.CreateText("Test").WithAudioData(null!, "audio/wav", 1.0f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var span3 = segment3.GetAudioSpan(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.True(span3.IsEmpty); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine("null 검증과 빈 케이스가 모두 안전하게 처리됨"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void ChatSegment_WithAudioMemory_ValidationTest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var testData = GenerateTestAudioData(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var memoryOwner = MemoryPool<byte>.Shared.Rent(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| testData.CopyTo(memoryOwner.Memory.Span); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 정상 케이스 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var validSegment = ChatSegment.CreateText("Test") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .WithAudioMemory(memoryOwner, 50, "audio/wav", 1.0f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(50, validSegment.GetAudioSpan().Length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // null audioMemoryOwner 테스트 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var nullException = Assert.Throws<ArgumentNullException>(() => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ChatSegment.CreateText("Test").WithAudioMemory(null!, 100, "audio/wav", 1.0f)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal("audioMemoryOwner", nullException.ParamName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // audioDataSize < 0 테스트 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var negativeException = Assert.Throws<ArgumentOutOfRangeException>(() => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ChatSegment.CreateText("Test").WithAudioMemory(memoryOwner, -1, "audio/wav", 1.0f)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal("audioDataSize", negativeException.ParamName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // audioDataSize > memory.Length 테스트 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var oversizeException = Assert.Throws<ArgumentOutOfRangeException>(() => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ChatSegment.CreateText("Test").WithAudioMemory(memoryOwner, memoryOwner.Memory.Length + 1, "audio/wav", 1.0f)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal("audioDataSize", oversizeException.ParamName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine("모든 소유권 이전 검증 테스트 통과"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Fact] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void ChatSegment_Dispose_MemoryOwnerReleaseTest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var testData = GenerateTestAudioData(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var memoryOwner = MemoryPool<byte>.Shared.Rent(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| testData.CopyTo(memoryOwner.Memory.Span); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var segment = ChatSegment.CreateText("Test") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .WithAudioMemory(memoryOwner, 100, "audio/wav", 1.0f); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Dispose 호출 전에는 정상 접근 가능 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.True(segment.HasAudio); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Assert.Equal(100, segment.GetAudioSpan().Length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Dispose 호출 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| segment.Dispose(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 메모리가 해제되었으므로 ObjectDisposedException 발생할 수 있음 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // (실제 구현에 따라 다를 수 있음) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _output.WriteLine("Dispose 호출 완료 - 메모리 소유자 해제됨"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private byte[] GenerateTestAudioData(int size) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.